import { FastifyInstance } from 'fastify';
import { prisma } from '../../config/database.js';
import { authMiddleware } from '../middleware/auth.middleware.js';
import { activateAuctionSchema } from '../middleware/validate.js';
import { successResponse, errorResponse } from '../../utils/helpers.js';
import { startAuctionTimer, stopAuctionTimer, extendAuctionTimer, getTimerRemaining } from '../../services/auction/timer.service.js';
import { emitAuctionStarted, emitAuctionEnded } from '../../websocket/socket.server.js';
import { sendAuctionStartedWebhook, sendAuctionEndedWebhook } from '../../services/cart/webhook-sender.js';

export async function auctionRoutes(app: FastifyInstance) {
  app.addHook('preHandler', authMiddleware);

  // POST /api/v1/auctions/activate
  app.post('/activate', async (request, reply) => {
    const parsed = activateAuctionSchema.safeParse(request.body);
    if (!parsed.success) {
      return errorResponse(reply, 'Validation error', 400, parsed.error.flatten());
    }

    const tenantId = request.tenantId!;
    const { productId, liveSessionId, mode, startingPrice, minBidIncrement, timeLimitSeconds } = parsed.data;

    // Verify session is live
    const session = await prisma.liveSession.findFirst({
      where: { id: liveSessionId, tenantId, status: 'live' },
    });
    if (!session) return errorResponse(reply, 'No active live session found', 404);

    // Verify product belongs to tenant
    const product = await prisma.product.findFirst({
      where: { id: productId, tenantId },
    });
    if (!product) return errorResponse(reply, 'Product not found', 404);

    // Check no active auction for this session
    const activeAuction = await prisma.auctionItem.findFirst({
      where: { liveSessionId, status: { in: ['active', 'countdown'] } },
    });
    if (activeAuction) {
      return errorResponse(reply, 'There is already an active auction in this session', 409);
    }

    // Update product status
    await prisma.product.update({
      where: { id: productId },
      data: { status: 'active' },
    });

    const auctionItem = await prisma.auctionItem.create({
      data: {
        liveSessionId,
        productId,
        mode,
        startingPrice,
        currentPrice: startingPrice,
        minBidIncrement: minBidIncrement ?? product.minBidIncrement,
        timeLimitSeconds,
        status: 'active',
        activatedAt: new Date(),
      },
      include: {
        product: { select: { name: true, imageUrl: true, stockQuantity: true } },
      },
    });

    // Start countdown timer if time limit set
    if (timeLimitSeconds && timeLimitSeconds > 0) {
      startAuctionTimer(auctionItem.id, tenantId, timeLimitSeconds);
    }

    // Emit to dashboard
    emitAuctionStarted(tenantId, {
      id: auctionItem.id,
      productName: auctionItem.product.name,
      mode,
      startingPrice,
      timeLimitSeconds: timeLimitSeconds ?? null,
    });

    // Send webhook to external e-commerce site
    sendAuctionStartedWebhook(tenantId, {
      id: auctionItem.id,
      mode,
      startingPrice,
      productName: auctionItem.product.name,
      timeLimitSeconds: timeLimitSeconds ?? null,
    }).catch(() => {});

    return successResponse(reply, auctionItem, 201);
  });

  // PUT /api/v1/auctions/:id/close
  app.put('/:id/close', async (request, reply) => {
    const { id } = request.params as { id: string };
    const tenantId = request.tenantId!;

    const auctionItem = await prisma.auctionItem.findFirst({
      where: {
        id,
        liveSession: { tenantId },
        status: { in: ['active', 'countdown'] },
      },
      include: { bids: { where: { status: 'pending' }, orderBy: { amount: 'desc' } } },
    });

    if (!auctionItem) {
      return errorResponse(reply, 'No active auction found', 404);
    }

    // Determine winner(s) based on mode
    if (auctionItem.mode === 'auction' && auctionItem.bids.length > 0) {
      // Highest bidder wins
      const winner = auctionItem.bids[0];
      await prisma.$transaction([
        prisma.auctionItem.update({
          where: { id },
          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, id: { not: winner.id }, status: 'pending' },
          data: { status: 'lost', processedAt: new Date() },
        }),
      ]);
    } else {
      // Fixed price or no bids — just close
      await prisma.auctionItem.update({
        where: { id },
        data: {
          status: auctionItem.bids.length > 0 ? 'sold' : 'cancelled',
          closedAt: new Date(),
        },
      });
    }

    const updated = await prisma.auctionItem.findUnique({
      where: { id },
      include: {
        product: { select: { name: true } },
        bids: { orderBy: { amount: 'desc' }, take: 10 },
      },
    });

    // Stop timer if running
    stopAuctionTimer(id);

    // Emit auction ended to dashboard
    if (updated) {
      const winnerBid = updated.bids.find(b => b.status === 'won');
      emitAuctionEnded(tenantId, {
        id: updated.id,
        productName: updated.product.name,
        winnerIgUsername: winnerBid?.igUsername,
        finalPrice: Number(updated.currentPrice),
      });

      sendAuctionEndedWebhook(tenantId, {
        id: updated.id,
        productName: updated.product.name,
        winnerIgUsername: winnerBid?.igUsername,
        finalPrice: Number(updated.currentPrice),
      }).catch(() => {});
    }

    return successResponse(reply, updated);
  });

  // GET /api/v1/auctions/:id/bids
  app.get('/:id/bids', async (request, reply) => {
    const { id } = request.params as { id: string };
    const tenantId = request.tenantId!;

    const auctionItem = await prisma.auctionItem.findFirst({
      where: { id, liveSession: { tenantId } },
    });
    if (!auctionItem) return errorResponse(reply, 'Auction item not found', 404);

    const bids = await prisma.bid.findMany({
      where: { auctionItemId: id },
      orderBy: { createdAt: 'desc' },
      include: {
        user: { select: { igUsername: true, displayName: true, trustScore: true } },
      },
    });

    return successResponse(reply, bids);
  });

  // PUT /api/v1/auctions/:id/extend
  app.put('/:id/extend', async (request, reply) => {
    const { id } = request.params as { id: string };
    const { seconds } = request.body as { seconds: number };
    const tenantId = request.tenantId!;

    if (!seconds || seconds < 1) {
      return errorResponse(reply, 'Invalid seconds value', 400);
    }

    const auctionItem = await prisma.auctionItem.findFirst({
      where: {
        id,
        liveSession: { tenantId },
        status: { in: ['active', 'countdown'] },
      },
    });
    if (!auctionItem) return errorResponse(reply, 'No active auction found', 404);

    const currentLimit = auctionItem.timeLimitSeconds ?? 0;
    const updated = await prisma.auctionItem.update({
      where: { id },
      data: { timeLimitSeconds: currentLimit + seconds },
    });

    // Extend the running timer
    extendAuctionTimer(id, seconds);

    return successResponse(reply, updated);
  });
}
