import { prisma } from '../../config/database.js';
import { logger } from '../../utils/logger.js';
import { emitCountdown, emitAuctionEnded } from '../../websocket/socket.server.js';
import { sendCartWebhook, sendAuctionEndedWebhook } from '../cart/webhook-sender.js';

interface ActiveTimer {
  auctionItemId: string;
  tenantId: string;
  intervalId: ReturnType<typeof setInterval>;
  endsAt: number;
}

const activeTimers = new Map<string, ActiveTimer>();

/**
 * Start a countdown timer for an auction item.
 * When timer reaches 0, the auction is auto-closed.
 */
export function startAuctionTimer(
  auctionItemId: string,
  tenantId: string,
  durationSeconds: number,
) {
  // Clear existing timer if any
  stopAuctionTimer(auctionItemId);

  const endsAt = Date.now() + durationSeconds * 1000;

  const intervalId = setInterval(async () => {
    const remaining = Math.max(0, Math.ceil((endsAt - Date.now()) / 1000));

    // Emit countdown every second
    emitCountdown(tenantId, { auctionItemId, secondsRemaining: remaining });

    if (remaining <= 0) {
      clearInterval(intervalId);
      activeTimers.delete(auctionItemId);
      await autoCloseAuction(auctionItemId, tenantId);
    }
  }, 1000);

  activeTimers.set(auctionItemId, {
    auctionItemId,
    tenantId,
    intervalId,
    endsAt,
  });

  logger.info({ auctionItemId, durationSeconds }, '[Timer] Auction timer started');
}

/**
 * Extend an active timer by additional seconds.
 */
export function extendAuctionTimer(auctionItemId: string, additionalSeconds: number) {
  const timer = activeTimers.get(auctionItemId);
  if (!timer) return false;

  // Stop old timer
  clearInterval(timer.intervalId);

  const newEndsAt = timer.endsAt + additionalSeconds * 1000;
  const remaining = Math.max(0, Math.ceil((newEndsAt - Date.now()) / 1000));

  // Start new interval with updated end time
  const intervalId = setInterval(async () => {
    const rem = Math.max(0, Math.ceil((newEndsAt - Date.now()) / 1000));
    emitCountdown(timer.tenantId, { auctionItemId, secondsRemaining: rem });

    if (rem <= 0) {
      clearInterval(intervalId);
      activeTimers.delete(auctionItemId);
      await autoCloseAuction(auctionItemId, timer.tenantId);
    }
  }, 1000);

  activeTimers.set(auctionItemId, {
    ...timer,
    intervalId,
    endsAt: newEndsAt,
  });

  logger.info({ auctionItemId, additionalSeconds, remaining }, '[Timer] Timer extended');
  return true;
}

/**
 * Stop and remove a timer.
 */
export function stopAuctionTimer(auctionItemId: string) {
  const timer = activeTimers.get(auctionItemId);
  if (timer) {
    clearInterval(timer.intervalId);
    activeTimers.delete(auctionItemId);
    logger.info({ auctionItemId }, '[Timer] Timer stopped');
  }
}

/**
 * Get remaining seconds for an auction timer.
 */
export function getTimerRemaining(auctionItemId: string): number | null {
  const timer = activeTimers.get(auctionItemId);
  if (!timer) return null;
  return Math.max(0, Math.ceil((timer.endsAt - Date.now()) / 1000));
}

/**
 * Auto-close auction when timer expires.
 */
async function autoCloseAuction(auctionItemId: string, tenantId: string) {
  try {
    const auctionItem = await prisma.auctionItem.findUnique({
      where: { id: auctionItemId },
      include: {
        product: { select: { name: true, stockQuantity: true } },
        bids: {
          where: { status: 'pending' },
          orderBy: { amount: 'desc' },
        },
      },
    });

    if (!auctionItem || !['active', 'countdown'].includes(auctionItem.status)) {
      return;
    }

    if (auctionItem.mode === 'auction' && auctionItem.bids.length > 0) {
      const winner = auctionItem.bids[0];

      await prisma.$transaction([
        prisma.auctionItem.update({
          where: { id: auctionItemId },
          data: {
            status: 'sold',
            closedAt: new Date(),
            winnerUserId: winner.userId,
            currentPrice: winner.amount,
          },
        }),
        prisma.bid.update({
          where: { id: winner.id },
          data: { status: 'won', processedAt: new Date() },
        }),
        prisma.bid.updateMany({
          where: { auctionItemId, id: { not: winner.id }, status: 'pending' },
          data: { status: 'lost', processedAt: new Date() },
        }),
      ]);

      // Create cart event for winner
      const cartEvent = await prisma.cartEvent.create({
        data: {
          tenantId,
          bidId: winner.id,
          userId: winner.userId,
          auctionItemId,
          status: 'pending',
        },
      });

      emitAuctionEnded(tenantId, {
        id: auctionItemId,
        productName: auctionItem.product.name,
        winnerIgUsername: winner.igUsername,
        finalPrice: Number(winner.amount),
      });

      // Send webhooks
      sendCartWebhook(cartEvent.id).catch(() => {});
      sendAuctionEndedWebhook(tenantId, {
        id: auctionItemId,
        productName: auctionItem.product.name,
        winnerIgUsername: winner.igUsername,
        finalPrice: Number(winner.amount),
      }).catch(() => {});

      logger.info({
        auctionItemId,
        winner: winner.igUsername,
        price: Number(winner.amount),
      }, '[Timer] Auction auto-closed with winner');
    } else {
      // No bids or fixed price mode — cancel
      await prisma.auctionItem.update({
        where: { id: auctionItemId },
        data: {
          status: auctionItem.bids.length > 0 ? 'sold' : 'cancelled',
          closedAt: new Date(),
        },
      });

      emitAuctionEnded(tenantId, {
        id: auctionItemId,
        productName: auctionItem.product.name,
        finalPrice: Number(auctionItem.currentPrice),
      });

      sendAuctionEndedWebhook(tenantId, {
        id: auctionItemId,
        productName: auctionItem.product.name,
        finalPrice: Number(auctionItem.currentPrice),
      }).catch(() => {});

      logger.info({ auctionItemId }, '[Timer] Auction auto-closed (no winner)');
    }
  } catch (err) {
    logger.error({ err, auctionItemId }, '[Timer] Error auto-closing auction');
  }
}

/**
 * Clean up all timers (for graceful shutdown).
 */
export function clearAllTimers() {
  for (const [id, timer] of activeTimers) {
    clearInterval(timer.intervalId);
  }
  activeTimers.clear();
  logger.info('[Timer] All timers cleared');
}
