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 { createRentalSchema, updateRentalSchema } from '../validators/rental.js';
import { AppError } from '../middleware/errorHandler.js';
import { getPlatformConfig, checkBlockedKeywords } from '../utils/moderation.js';
import { checkAvailability } from '../utils/rental.js';

const router = Router();

const rentalSelect = {
  id: true, title: true, description: true, category: true, location: true,
  dailyPrice: true, monthlyPrice: true, depositAmount: true, details: true,
  amenities: true, rules: true, cancellationPolicy: true,
  minDays: true, maxDays: true, minMonths: true, maxMonths: true,
  status: true, viewCount: true, isFeatured: true, isVerified: true,
  rejectionReason: true,
  createdAt: true, updatedAt: true, landlordId: true,
  landlord: { select: { id: true, fullName: true, nickname: true, avatar: true, rating: true, location: true, createdAt: true, landlordVerified: true, showEmail: true, showPhone: true, showLocation: true } },
  images: { orderBy: { order: 'asc' as const } },
  _count: { select: { favorites: true, bookings: true, reviews: true } },
};

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

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

// --- Favorites list ---
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.rentalFavorite.findMany({
        where: { userId: req.userId! },
        include: { rentalListing: { select: rentalSelect } },
        orderBy: { createdAt: 'desc' },
        skip, take,
      }),
      prisma.rentalFavorite.count({ where: { userId: req.userId! } }),
    ]);

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

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

// --- Search/list active rentals ---
router.get('/', optionalAuth, async (req, res, next) => {
  try {
    const { page = '1', pageSize = '20', category, search, sort = 'newest', priceMin, priceMax, periodType, location } = 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 (location && typeof location === 'string') {
      where.location = { contains: location, mode: 'insensitive' };
    }
    if (search) {
      where.OR = [
        { title: { contains: search as string, mode: 'insensitive' } },
        { description: { contains: search as string, mode: 'insensitive' } },
        { location: { contains: search as string, mode: 'insensitive' } },
      ];
    }

    // Price filters
    if (periodType === 'DAILY' || priceMin || priceMax) {
      const priceField = periodType === 'MONTHLY' ? 'monthlyPrice' : 'dailyPrice';
      const priceFilter: Record<string, unknown> = {};
      if (priceMin) priceFilter.gte = parseFloat(priceMin as string);
      if (priceMax) priceFilter.lte = parseFloat(priceMax as string);
      if (Object.keys(priceFilter).length > 0) {
        where[priceField] = priceFilter;
      }
    }

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

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

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

    const listings = data.map(l => ({ ...l, isFavorited: favIds.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 rental ---
router.get('/:id', optionalAuth, async (req, res, next) => {
  try {
    const rental = await prisma.rentalListing.findUnique({
      where: { id: req.params.id },
      select: {
        ...rentalSelect,
        landlord: { select: { id: true, email: true, fullName: true, nickname: true, avatar: true, phone: true, location: true, bio: true, rating: true, landlordVerified: true, showEmail: true, showPhone: true, showLocation: true, createdAt: true } },
        reviews: {
          select: {
            id: true, rating: true, comment: true, landlordResponse: true, createdAt: true,
            tenant: { select: { id: true, fullName: true, avatar: true } },
          },
          orderBy: { createdAt: 'desc' as const },
          take: 20,
        },
      },
    });
    if (!rental || rental.status === 'DELETED') throw new AppError(404, 'Rental not found');

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

    let isFavorited = false;
    if (req.userId) {
      const fav = await prisma.rentalFavorite.findUnique({
        where: { userId_rentalListingId: { userId: req.userId, rentalListingId: rental.id } },
      });
      isFavorited = !!fav;
    }

    // Average rating
    const avgRating = rental.reviews.length > 0
      ? rental.reviews.reduce((sum, r) => sum + r.rating, 0) / rental.reviews.length
      : 0;

    // Privacy
    const landlord: Record<string, unknown> = { ...rental.landlord };
    if (!rental.landlord.showEmail) delete landlord.email;
    if (!rental.landlord.showPhone) delete landlord.phone;
    if (!rental.landlord.showLocation) delete landlord.location;

    res.json({ ...rental, landlord, isFavorited, avgRating });
  } catch (error) {
    next(error);
  }
});

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

    // Set user as landlord
    await prisma.user.update({ where: { id: req.userId }, data: { isLandlord: true } });

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

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

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

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

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

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

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

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

// --- Pause rental ---
router.post('/:id/pause', authenticate, async (req, res, next) => {
  try {
    const existing = await prisma.rentalListing.findUnique({ where: { id: req.params.id } });
    if (!existing) throw new AppError(404, 'Rental not found');
    if (existing.landlordId !== req.userId) throw new AppError(403, 'Not authorized');
    if (existing.status !== 'ACTIVE') throw new AppError(400, 'Can only pause active rentals');

    const rental = await prisma.rentalListing.update({
      where: { id: req.params.id },
      data: { status: 'PAUSED' },
      select: rentalSelect,
    });
    res.json(rental);
  } catch (error) {
    next(error);
  }
});

// --- Upload images ---
router.post('/:id/images', authenticate, upload.array('images', 10), async (req, res, next) => {
  try {
    const existing = await prisma.rentalListing.findUnique({ where: { id: req.params.id } });
    if (!existing) throw new AppError(404, 'Rental not found');
    if (existing.landlordId !== 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.rentalImage.count({ where: { rentalListingId: req.params.id } });

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

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

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

    const existing = await prisma.rentalFavorite.findUnique({
      where: { userId_rentalListingId: { userId: req.userId!, rentalListingId: req.params.id! } },
    });

    if (existing) {
      await prisma.rentalFavorite.delete({ where: { id: existing.id } });
      res.json({ isFavorited: false });
    } else {
      await prisma.rentalFavorite.create({ data: { userId: req.userId!, rentalListingId: req.params.id! } });
      res.json({ isFavorited: true });
    }
  } catch (error) {
    next(error);
  }
});

// --- Availability ---
router.get('/:id/availability', async (req, res, next) => {
  try {
    const { start, end } = req.query;
    const startDate = start ? new Date(start as string) : new Date();
    const endDate = end ? new Date(end as string) : new Date(Date.now() + 90 * 24 * 60 * 60 * 1000);

    const [blocks, bookings] = await Promise.all([
      prisma.availabilityBlock.findMany({
        where: {
          rentalListingId: req.params.id,
          OR: [
            { startDate: { lte: endDate }, endDate: { gte: startDate } },
          ],
        },
        orderBy: { startDate: 'asc' },
      }),
      prisma.booking.findMany({
        where: {
          rentalListingId: req.params.id,
          status: { in: ['CONFIRMED', 'ACTIVE'] },
          startDate: { lte: endDate },
          endDate: { gte: startDate },
        },
        select: { id: true, startDate: true, endDate: true, status: true },
        orderBy: { startDate: 'asc' },
      }),
    ]);

    res.json({ blocks, bookings });
  } catch (error) {
    next(error);
  }
});

router.post('/:id/availability', authenticate, async (req, res, next) => {
  try {
    const existing = await prisma.rentalListing.findUnique({ where: { id: req.params.id } });
    if (!existing) throw new AppError(404, 'Rental not found');
    if (existing.landlordId !== req.userId) throw new AppError(403, 'Not authorized');

    const { startDate, endDate, reason } = req.body;
    if (!startDate || !endDate) throw new AppError(400, 'Start and end dates required');

    const block = await prisma.availabilityBlock.create({
      data: {
        rentalListingId: req.params.id!,
        startDate: new Date(startDate),
        endDate: new Date(endDate),
        isBlocked: true,
        reason,
      },
    });

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

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

    const block = await prisma.availabilityBlock.findUnique({ where: { id: req.params.blockId } });
    if (!block || block.rentalListingId !== req.params.id) throw new AppError(404, 'Block not found');

    await prisma.availabilityBlock.delete({ where: { id: req.params.blockId } });
    res.json({ message: 'Block deleted' });
  } catch (error) {
    next(error);
  }
});

export default router;
