import { Router, Response, Request } from 'express';
import { BookLesson, LessonBooking } from '../models/index.js';
import { authenticate, requireRole, AuthRequest } from '../middleware/auth.js';

const router = Router();

// GET /api/book-lessons — public, returns page content
router.get('/', async (req: Request, res: Response): Promise<void> => {
  try {
    let page = await BookLesson.findOne();
    if (!page) {
      page = new BookLesson();
      await page.save();
    }
    res.json(page);
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
});

// PUT /api/book-lessons — admin only, update page content
router.put(
  '/',
  authenticate,
  requireRole('admin'),
  async (req: AuthRequest, res: Response): Promise<void> => {
    try {
      let page = await BookLesson.findOne();
      if (!page) {
        page = new BookLesson(req.body);
      } else {
        Object.assign(page, req.body);
      }
      await page.save();
      res.json(page);
    } catch (error) {
      res.status(500).json({ error: 'Server error' });
    }
  }
);

// GET /api/book-lessons/availability?date=YYYY-MM-DD — public
router.get('/availability', async (req: Request, res: Response): Promise<void> => {
  try {
    const { date } = req.query;
    if (!date || typeof date !== 'string') {
      res.status(400).json({ error: 'date query parameter is required (YYYY-MM-DD)' });
      return;
    }

    const page = await BookLesson.findOne();
    if (!page) {
      res.json({ slots: [] });
      return;
    }

    const targetDate = new Date(date + 'T00:00:00');
    const dayOfWeek = targetDate.getDay();

    if (!page.availableDays.includes(dayOfWeek)) {
      res.json({ slots: [], unavailableReason: 'Day not available' });
      return;
    }

    const startOfDay = new Date(date + 'T00:00:00');
    const endOfDay = new Date(date + 'T23:59:59');

    const existingBookings = await LessonBooking.find({
      date: { $gte: startOfDay, $lte: endOfDay },
      status: { $ne: 'cancelled' },
    });

    const slots = page.timeSlots.map((slot) => {
      const slotKey = `${slot.startTime}-${slot.endTime}`;
      const bookingsForSlot = existingBookings.filter((b) => b.timeSlot === slotKey);
      return {
        startTime: slot.startTime,
        endTime: slot.endTime,
        available: bookingsForSlot.length < page.maxCapacityPerSlot,
        bookedCount: bookingsForSlot.length,
        maxCapacity: page.maxCapacityPerSlot,
      };
    });

    res.json({ date, slots });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
});

// POST /api/book-lessons/bookings — public, create a booking
router.post('/bookings', async (req: Request, res: Response): Promise<void> => {
  try {
    const { date, timeSlot, firstName, lastName, email, phone, golfId } = req.body;

    if (!date || !timeSlot || !firstName || !lastName || !email || !phone) {
      res.status(400).json({ error: 'date, timeSlot, firstName, lastName, email, and phone are required' });
      return;
    }

    const page = await BookLesson.findOne();
    if (!page) {
      res.status(500).json({ error: 'Booking system not configured' });
      return;
    }

    const targetDate = new Date(date + 'T00:00:00');
    const dayOfWeek = targetDate.getDay();

    if (!page.availableDays.includes(dayOfWeek)) {
      res.status(400).json({ error: 'Selected date is not available for booking' });
      return;
    }

    const validSlot = page.timeSlots.some(
      (s) => `${s.startTime}-${s.endTime}` === timeSlot
    );
    if (!validSlot) {
      res.status(400).json({ error: 'Invalid time slot' });
      return;
    }

    const startOfDay = new Date(date + 'T00:00:00');
    const endOfDay = new Date(date + 'T23:59:59');

    const existingCount = await LessonBooking.countDocuments({
      date: { $gte: startOfDay, $lte: endOfDay },
      timeSlot,
      status: { $ne: 'cancelled' },
    });

    if (existingCount >= page.maxCapacityPerSlot) {
      res.status(400).json({ error: 'This time slot is fully booked' });
      return;
    }

    const booking = new LessonBooking({
      date: targetDate,
      timeSlot,
      firstName,
      lastName,
      email,
      phone,
      golfId,
    });
    await booking.save();

    res.status(201).json({ message: 'Booking submitted successfully', booking });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
});

// GET /api/book-lessons/bookings — admin only, paginated list
router.get(
  '/bookings',
  authenticate,
  requireRole('admin'),
  async (req: AuthRequest, res: Response): Promise<void> => {
    try {
      const { page = 1, limit = 20, status } = req.query;

      const filter: Record<string, unknown> = {};
      if (status && status !== 'all') {
        filter.status = status;
      }

      const bookings = await LessonBooking.find(filter)
        .sort({ date: -1, createdAt: -1 })
        .skip((Number(page) - 1) * Number(limit))
        .limit(Number(limit));
      const total = await LessonBooking.countDocuments(filter);

      res.json({
        bookings,
        pagination: {
          page: Number(page),
          limit: Number(limit),
          total,
          pages: Math.ceil(total / Number(limit)),
        },
      });
    } catch (error) {
      res.status(500).json({ error: 'Server error' });
    }
  }
);

// PUT /api/book-lessons/bookings/:id — admin only, update status/notes
router.put(
  '/bookings/:id',
  authenticate,
  requireRole('admin'),
  async (req: AuthRequest, res: Response): Promise<void> => {
    try {
      const { id } = req.params;
      const { status, notes } = req.body;

      const booking = await LessonBooking.findById(id);
      if (!booking) {
        res.status(404).json({ error: 'Booking not found' });
        return;
      }

      if (status) booking.status = status;
      if (notes !== undefined) booking.notes = notes;
      await booking.save();

      res.json(booking);
    } catch (error) {
      res.status(500).json({ error: 'Server error' });
    }
  }
);

export default router;
