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';

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,
  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 } },
};

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' } },
      ];
    }

    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);
  }
});

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;
    }

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

router.post('/', authenticate, validate(createListingSchema), async (req, res, next) => {
  try {
    const listing = await prisma.listing.create({
      data: { ...req.body, sellerId: req.userId!, status: 'DRAFT' },
      select: listingSelect,
    });
    res.status(201).json(listing);
  } catch (error) {
    next(error);
  }
});

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');

    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 (bypasses Stripe in dev, requires payment in prod)
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') throw new AppError(400, 'Listing is not in draft status');

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

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);
  }
});

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);
  }
});

router.post('/:id/favorite', authenticate, async (req, res, next) => {
  try {
    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! } });
      res.json({ isFavorited: true });
    }
  } catch (error) {
    next(error);
  }
});

export default router;
