import { Router } from 'express';
import { prisma } from '../config/database.js';
import { authenticate, optionalAuth } from '../middleware/auth.js';
import { validate } from '../middleware/validate.js';
import { upload } from '../middleware/upload.js';
import { createListingSchema, updateListingSchema } from '../validators/listing.js';
import { AppError } from '../middleware/errorHandler.js';
import { getBlockedUserIds } from '../utils/blocked.js';
import { getPlatformConfig, checkBlockedKeywords } from '../utils/moderation.js';

const router = Router();

const listingSelect = {
  id: true, title: true, description: true, price: true, obo: true,
  category: true, condition: true, status: true, location: true, viewCount: true,
  isFeatured: true,
  createdAt: true, updatedAt: true, sellerId: true,
  seller: { select: { id: true, fullName: true, nickname: true, avatar: true, rating: true, location: true, createdAt: true, showEmail: true, showPhone: true, showLocation: true } },
  images: { orderBy: { order: 'asc' as const } },
  _count: { select: { favorites: true } },
};

// --- Sold items (must be before /:id) ---
router.get('/sold', authenticate, async (req, res, next) => {
  try {
    const listings = await prisma.listing.findMany({
      where: { sellerId: req.userId, status: 'SOLD' },
      select: {
        ...listingSelect,
        offers: {
          where: { status: 'ACCEPTED' },
          take: 1,
          include: {
            buyer: { select: { id: true, fullName: true, nickname: true, avatar: true } },
          },
        },
      },
      orderBy: { updatedAt: 'desc' },
    });

    const soldItems = listings.map(listing => {
      const acceptedOffer = listing.offers[0];
      return {
        ...listing,
        offers: undefined,
        salePrice: acceptedOffer?.amount ?? listing.price,
        buyer: acceptedOffer?.buyer ?? null,
        soldDate: acceptedOffer?.updatedAt ?? listing.updatedAt,
      };
    });

    // Earnings stats
    const totalEarnings = soldItems.reduce((sum, item) => sum + (item.salePrice || 0), 0);

    res.json({
      data: soldItems,
      stats: {
        totalSold: soldItems.length,
        totalEarnings,
      },
    });
  } catch (error) {
    next(error);
  }
});

// --- My listings (must be before /:id) ---
router.get('/mine', authenticate, async (req, res, next) => {
  try {
    const { status } = req.query;
    const where: Record<string, unknown> = { sellerId: req.userId };
    if (status && typeof status === 'string') {
      where.status = status;
    } else {
      where.status = { not: 'DELETED' };
    }

    const listings = await prisma.listing.findMany({
      where,
      select: listingSelect,
      orderBy: { createdAt: 'desc' },
    });
    res.json(listings);
  } catch (error) {
    next(error);
  }
});

// --- Favorites list (must be before /:id) ---
router.get('/favorites', authenticate, async (req, res, next) => {
  try {
    const { page = '1', pageSize = '20' } = req.query;
    const skip = (parseInt(page as string) - 1) * parseInt(pageSize as string);
    const take = parseInt(pageSize as string);

    const [favorites, total] = await Promise.all([
      prisma.favorite.findMany({
        where: { userId: req.userId! },
        include: {
          listing: {
            select: listingSelect,
          },
        },
        orderBy: { createdAt: 'desc' },
        skip,
        take,
      }),
      prisma.favorite.count({ where: { userId: req.userId! } }),
    ]);

    const data = favorites
      .filter(f => f.listing.status === 'ACTIVE')
      .map(f => ({ ...f.listing, isFavorited: true }));

    res.json({
      data,
      total,
      page: parseInt(page as string),
      pageSize: take,
      totalPages: Math.ceil(total / take),
    });
  } catch (error) {
    next(error);
  }
});

// --- List active listings ---
router.get('/', optionalAuth, async (req, res, next) => {
  try {
    const { page = '1', pageSize = '20', category, search, sort = 'newest', condition } = req.query;
    const skip = (parseInt(page as string) - 1) * parseInt(pageSize as string);
    const take = parseInt(pageSize as string);

    const where: Record<string, unknown> = { status: 'ACTIVE' };
    if (category) where.category = category;
    if (condition) where.condition = condition;
    if (search) {
      where.OR = [
        { title: { contains: search as string, mode: 'insensitive' } },
        { description: { contains: search as string, mode: 'insensitive' } },
      ];
    }

    // Exclude blocked users' listings
    if (req.userId) {
      const blockedIds = await getBlockedUserIds(req.userId);
      if (blockedIds.length > 0) {
        where.sellerId = { notIn: blockedIds };
      }
    }

    const orderBy = sort === 'price_asc' ? { price: 'asc' as const }
      : sort === 'price_desc' ? { price: 'desc' as const }
      : sort === 'popular' ? { viewCount: 'desc' as const }
      : { createdAt: 'desc' as const };

    const [data, total] = await Promise.all([
      prisma.listing.findMany({ where, select: listingSelect, skip, take, orderBy }),
      prisma.listing.count({ where }),
    ]);

    let favorites: Set<string> = new Set();
    if (req.userId) {
      const favs = await prisma.favorite.findMany({
        where: { userId: req.userId, listingId: { in: data.map(l => l.id) } },
        select: { listingId: true },
      });
      favorites = new Set(favs.map(f => f.listingId));
    }

    const listings = data.map(l => ({ ...l, isFavorited: favorites.has(l.id) }));

    res.json({
      data: listings,
      total,
      page: parseInt(page as string),
      pageSize: take,
      totalPages: Math.ceil(total / take),
    });
  } catch (error) {
    next(error);
  }
});

// --- Get single listing ---
router.get('/:id', optionalAuth, async (req, res, next) => {
  try {
    const listing = await prisma.listing.findUnique({
      where: { id: req.params.id },
      select: { ...listingSelect, seller: { select: { id: true, email: true, fullName: true, nickname: true, avatar: true, phone: true, location: true, bio: true, rating: true, showEmail: true, showPhone: true, showLocation: true, createdAt: true } } },
    });
    if (!listing || listing.status === 'DELETED') throw new AppError(404, 'Listing not found');

    await prisma.listing.update({ where: { id: req.params.id }, data: { viewCount: { increment: 1 } } });

    let isFavorited = false;
    if (req.userId) {
      const fav = await prisma.favorite.findUnique({
        where: { userId_listingId: { userId: req.userId, listingId: listing.id } },
      });
      isFavorited = !!fav;
    }

    // Enforce seller privacy flags
    const seller: Record<string, unknown> = { ...listing.seller };
    if (!listing.seller.showEmail) delete seller.email;
    if (!listing.seller.showPhone) delete seller.phone;
    if (!listing.seller.showLocation) delete seller.location;

    res.json({ ...listing, seller, isFavorited });
  } catch (error) {
    next(error);
  }
});

// --- Create listing ---
router.post('/', authenticate, validate(createListingSchema), async (req, res, next) => {
  try {
    const config = await getPlatformConfig();
    const textToCheck = `${req.body.title} ${req.body.description}`;
    const blockedWord = checkBlockedKeywords(textToCheck, config.blockedKeywords);

    const listing = await prisma.listing.create({
      data: { ...req.body, sellerId: req.userId!, status: blockedWord ? 'PENDING_REVIEW' : 'DRAFT' },
      select: listingSelect,
    });
    res.status(201).json(listing);
  } catch (error) {
    next(error);
  }
});

// --- Update listing ---
router.put('/:id', authenticate, validate(updateListingSchema), async (req, res, next) => {
  try {
    const existing = await prisma.listing.findUnique({ where: { id: req.params.id } });
    if (!existing) throw new AppError(404, 'Listing not found');
    if (existing.sellerId !== req.userId) throw new AppError(403, 'Not authorized');
    if (existing.status === 'SOLD') throw new AppError(400, 'Cannot edit a sold listing');
    if (existing.status === 'DELETED') throw new AppError(400, 'Cannot edit a deleted listing');

    const listing = await prisma.listing.update({
      where: { id: req.params.id },
      data: req.body,
      select: listingSelect,
    });
    res.json(listing);
  } catch (error) {
    next(error);
  }
});

// --- Activate listing ---
router.post('/:id/activate', authenticate, async (req, res, next) => {
  try {
    const existing = await prisma.listing.findUnique({ where: { id: req.params.id } });
    if (!existing) throw new AppError(404, 'Listing not found');
    if (existing.sellerId !== req.userId) throw new AppError(403, 'Not authorized');
    if (existing.status !== 'DRAFT' && existing.status !== 'PENDING_REVIEW') throw new AppError(400, 'Listing cannot be activated');

    const config = await getPlatformConfig();
    const textToCheck = `${existing.title} ${existing.description}`;
    const blockedWord = checkBlockedKeywords(textToCheck, config.blockedKeywords);
    const newStatus = (!config.autoApprove || blockedWord) ? 'PENDING_REVIEW' : 'ACTIVE';

    const listing = await prisma.listing.update({
      where: { id: req.params.id },
      data: { status: newStatus },
      select: listingSelect,
    });
    res.json(listing);
  } catch (error) {
    next(error);
  }
});

// --- Delete listing ---
router.delete('/:id', authenticate, async (req, res, next) => {
  try {
    const existing = await prisma.listing.findUnique({ where: { id: req.params.id } });
    if (!existing) throw new AppError(404, 'Listing not found');
    if (existing.sellerId !== req.userId) throw new AppError(403, 'Not authorized');

    await prisma.listing.update({
      where: { id: req.params.id },
      data: { status: 'DELETED' },
    });
    res.json({ message: 'Listing deleted' });
  } catch (error) {
    next(error);
  }
});

// --- Upload images ---
router.post('/:id/images', authenticate, upload.array('images', 6), async (req, res, next) => {
  try {
    const existing = await prisma.listing.findUnique({ where: { id: req.params.id } });
    if (!existing) throw new AppError(404, 'Listing not found');
    if (existing.sellerId !== req.userId) throw new AppError(403, 'Not authorized');

    const files = req.files as Express.Multer.File[];
    if (!files?.length) throw new AppError(400, 'No files uploaded');

    const existingImages = await prisma.listingImage.count({ where: { listingId: req.params.id } });

    const images = await Promise.all(
      files.map((file, i) =>
        prisma.listingImage.create({
          data: {
            url: `/uploads/${file.filename}`,
            order: existingImages + i,
            listingId: req.params.id!,
            uploadedBy: req.userId!,
          },
        })
      )
    );

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

// --- Delete image ---
router.delete('/:id/images/:imageId', authenticate, async (req, res, next) => {
  try {
    const existing = await prisma.listing.findUnique({ where: { id: req.params.id } });
    if (!existing) throw new AppError(404, 'Listing not found');
    if (existing.sellerId !== req.userId) throw new AppError(403, 'Not authorized');

    const image = await prisma.listingImage.findUnique({ where: { id: req.params.imageId } });
    if (!image || image.listingId !== req.params.id) throw new AppError(404, 'Image not found');

    await prisma.listingImage.delete({ where: { id: req.params.imageId } });
    res.json({ message: 'Image deleted' });
  } catch (error) {
    next(error);
  }
});

// --- Reorder images ---
router.put('/:id/images/reorder', authenticate, async (req, res, next) => {
  try {
    const existing = await prisma.listing.findUnique({ where: { id: req.params.id } });
    if (!existing) throw new AppError(404, 'Listing not found');
    if (existing.sellerId !== req.userId) throw new AppError(403, 'Not authorized');

    const { imageIds } = req.body;
    if (!Array.isArray(imageIds)) throw new AppError(400, 'imageIds must be an array');

    await Promise.all(
      imageIds.map((imageId: string, index: number) =>
        prisma.listingImage.update({
          where: { id: imageId },
          data: { order: index },
        })
      )
    );

    const images = await prisma.listingImage.findMany({
      where: { listingId: req.params.id },
      orderBy: { order: 'asc' },
    });
    res.json(images);
  } catch (error) {
    next(error);
  }
});

// --- Toggle favorite ---
router.post('/:id/favorite', authenticate, async (req, res, next) => {
  try {
    const listing = await prisma.listing.findUnique({ where: { id: req.params.id } });
    if (!listing) throw new AppError(404, 'Listing not found');

    const existing = await prisma.favorite.findUnique({
      where: { userId_listingId: { userId: req.userId!, listingId: req.params.id! } },
    });

    if (existing) {
      await prisma.favorite.delete({ where: { id: existing.id } });
      res.json({ isFavorited: false });
    } else {
      await prisma.favorite.create({ data: { userId: req.userId!, listingId: req.params.id! } });

      // Notify seller (if not self)
      if (listing.sellerId !== req.userId) {
        const user = await prisma.user.findUnique({ where: { id: req.userId }, select: { fullName: true } });
        const notification = await prisma.notification.create({
          data: {
            userId: listing.sellerId,
            type: 'ITEM_FAVORITED',
            title: 'Item Favorited',
            body: `${user?.fullName || 'Someone'} favorited your listing "${listing.title}"`,
            data: { listingId: listing.id },
          },
        });

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

      res.json({ isFavorited: true });
    }
  } catch (error) {
    next(error);
  }
});

export default router;
