import { Router } from 'express';
import { prisma } from '../config/database.js';
import { authenticate } from '../middleware/auth.js';
import { validate } from '../middleware/validate.js';
import { createOfferSchema, respondOfferSchema } from '../validators/offer.js';
import { AppError } from '../middleware/errorHandler.js';
import { getBlockedUserIds } from '../utils/blocked.js';

const router = Router();

const offerInclude = {
  listing: { include: { images: { take: 1, orderBy: { order: 'asc' as const } } } },
  buyer: { select: { id: true, fullName: true, nickname: true, avatar: true } },
  seller: { select: { id: true, fullName: true, nickname: true, avatar: true } },
};

// --- List offers ---
router.get('/', authenticate, async (req, res, next) => {
  try {
    const { type = 'received', sort = 'newest' } = req.query;
    const where = type === 'sent'
      ? { buyerId: req.userId }
      : { sellerId: req.userId };

    const orderBy = sort === 'price_high' ? { amount: 'desc' as const }
      : sort === 'price_low' ? { amount: 'asc' as const }
      : { createdAt: 'desc' as const };

    const offers = await prisma.offer.findMany({
      where,
      include: offerInclude,
      orderBy,
    });

    // Check for expired offers and mark them
    const now = new Date();
    const updatedOffers = await Promise.all(offers.map(async (offer) => {
      if (offer.status === 'PENDING' && offer.expiresAt && offer.expiresAt < now) {
        const updated = await prisma.offer.update({
          where: { id: offer.id },
          data: { status: 'EXPIRED' },
          include: offerInclude,
        });
        return updated;
      }
      return offer;
    }));

    res.json(updatedOffers);
  } catch (error) {
    next(error);
  }
});

// --- Get single offer ---
router.get('/:id', authenticate, async (req, res, next) => {
  try {
    const offer = await prisma.offer.findUnique({
      where: { id: req.params.id },
      include: offerInclude,
    });
    if (!offer) throw new AppError(404, 'Offer not found');
    if (offer.buyerId !== req.userId && offer.sellerId !== req.userId) {
      throw new AppError(403, 'Not authorized');
    }

    // Check expiry
    if (offer.status === 'PENDING' && offer.expiresAt && offer.expiresAt < new Date()) {
      const updated = await prisma.offer.update({
        where: { id: offer.id },
        data: { status: 'EXPIRED' },
        include: offerInclude,
      });
      return res.json(updated);
    }

    res.json(offer);
  } catch (error) {
    next(error);
  }
});

// --- Create offer ---
router.post('/', authenticate, validate(createOfferSchema), async (req, res, next) => {
  try {
    const { amount, message, listingId } = req.body;

    const listing = await prisma.listing.findUnique({ where: { id: listingId } });
    if (!listing) throw new AppError(404, 'Listing not found');
    if (listing.status !== 'ACTIVE') throw new AppError(400, 'Listing is not active');
    if (listing.sellerId === req.userId) throw new AppError(400, 'Cannot make offer on your own listing');

    // Check blocked users
    const blockedIds = await getBlockedUserIds(req.userId!);
    if (blockedIds.includes(listing.sellerId)) {
      throw new AppError(403, 'Cannot make offer to this user');
    }

    // Prevent duplicate pending offers
    const existingOffer = await prisma.offer.findFirst({
      where: { buyerId: req.userId, listingId, status: 'PENDING' },
    });
    if (existingOffer) throw new AppError(409, 'You already have a pending offer on this listing');

    const offer = await prisma.offer.create({
      data: {
        amount,
        message,
        listingId,
        buyerId: req.userId!,
        sellerId: listing.sellerId,
        expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
      },
      include: offerInclude,
    });

    const notification = await prisma.notification.create({
      data: {
        userId: listing.sellerId,
        type: 'NEW_OFFER',
        title: 'New Offer',
        body: `${offer.buyer.fullName} made an offer of $${amount} for ${listing.title}`,
        data: { listingId, offerId: offer.id, amount },
      },
    });

    const io = req.app.get('io');
    if (io) {
      io.to(`user:${listing.sellerId}`).emit('new_notification', notification);
      io.to(`user:${listing.sellerId}`).emit('offer_update', offer);
    }

    res.status(201).json(offer);
  } catch (error) {
    next(error);
  }
});

// --- Cancel offer (buyer only) ---
router.delete('/:id', authenticate, async (req, res, next) => {
  try {
    const offer = await prisma.offer.findUnique({ where: { id: req.params.id } });
    if (!offer) throw new AppError(404, 'Offer not found');
    if (offer.buyerId !== req.userId) throw new AppError(403, 'Not authorized');
    if (offer.status !== 'PENDING') throw new AppError(400, 'Can only cancel pending offers');

    const updated = await prisma.offer.update({
      where: { id: req.params.id },
      data: { status: 'CANCELLED' },
      include: offerInclude,
    });

    const io = req.app.get('io');
    if (io) {
      io.to(`user:${offer.sellerId}`).emit('offer_update', updated);
    }

    res.json(updated);
  } catch (error) {
    next(error);
  }
});

// --- Respond to offer (seller or buyer responding to counter) ---
router.patch('/:id', authenticate, validate(respondOfferSchema), async (req, res, next) => {
  try {
    const existing = await prisma.offer.findUnique({ where: { id: req.params.id }, include: { listing: true } });
    if (!existing) throw new AppError(404, 'Offer not found');

    const { status, counterAmount } = req.body;

    // Buyer can respond to COUNTERED offers (accept or decline)
    if (existing.status === 'COUNTERED' && existing.buyerId === req.userId) {
      if (status !== 'ACCEPTED' && status !== 'DECLINED') {
        throw new AppError(400, 'Can only accept or decline a counter offer');
      }
    } else if (existing.sellerId === req.userId) {
      // Seller responding to PENDING offer
      if (existing.status !== 'PENDING') throw new AppError(400, 'Offer already responded to');
    } else {
      throw new AppError(403, 'Not authorized');
    }

    // Validate counter amount
    if (status === 'COUNTERED' && !counterAmount) {
      throw new AppError(400, 'Counter amount is required when countering an offer');
    }

    const offer = await prisma.offer.update({
      where: { id: req.params.id },
      data: { status, counterAmount },
      include: offerInclude,
    });

    if (status === 'ACCEPTED') {
      await prisma.listing.update({ where: { id: existing.listingId }, data: { status: 'SOLD' } });
      await prisma.offer.updateMany({
        where: { listingId: existing.listingId, id: { not: existing.id }, status: 'PENDING' },
        data: { status: 'DECLINED' },
      });

      // Create commission payment
      try {
        const { getPlatformConfig } = await import('../utils/moderation.js');
        const config = await getPlatformConfig();
        const saleAmount = existing.status === 'COUNTERED' ? (existing.counterAmount || existing.amount) : existing.amount;
        const commission = saleAmount * (config.commissionPercent / 100);
        if (commission > 0) {
          await prisma.payment.create({
            data: {
              userId: existing.sellerId,
              listingId: existing.listingId,
              amount: commission,
              status: 'COMPLETED',
              type: 'COMMISSION',
              description: `${config.commissionPercent}% commission on sale`,
            },
          });
        }
      } catch {}
    }

    const recipientId = existing.buyerId === req.userId ? existing.sellerId : existing.buyerId;
    const notificationType = status === 'ACCEPTED' ? 'OFFER_ACCEPTED' as const
      : status === 'DECLINED' ? 'OFFER_DECLINED' as const
      : 'NEW_OFFER' as const;

    const notification = await prisma.notification.create({
      data: {
        userId: recipientId,
        type: notificationType,
        title: status === 'ACCEPTED' ? 'Offer Accepted' : status === 'DECLINED' ? 'Offer Declined' : 'Counter Offer',
        body: status === 'COUNTERED'
          ? `Counter offer of $${counterAmount} for ${existing.listing.title}`
          : `Your offer for ${existing.listing.title} was ${status.toLowerCase()}`,
        data: { offerId: existing.id, listingId: existing.listingId },
      },
    });

    const io = req.app.get('io');
    if (io) {
      io.to(`user:${recipientId}`).emit('new_notification', notification);
      io.to(`user:${existing.buyerId}`).emit('offer_update', offer);
      io.to(`user:${existing.sellerId}`).emit('offer_update', offer);
    }

    res.json(offer);
  } catch (error) {
    next(error);
  }
});

export default router;
