const express = require("express");
const Event = require("../models/Event");
const User = require("../models/User");
const auth = require("../middleware/auth");
const { asyncHandler } = require("../middleware/errorHandler");
const {
  createEventValidation,
  eventIdValidation,
} = require("../middleware/validators/eventValidator");
const { paginate, buildPaginatedResponse } = require("../middleware/pagination");
const couchdbService = require("../services/couchdbService");
const { getCacheMiddleware, invalidateCacheByPattern } = require("../middleware/cache");

const router = express.Router();

// Get all events (with pagination)
router.get(
  "/",
  paginate,
  getCacheMiddleware(120), // Cache for 2 minutes
  asyncHandler(async (req, res) => {
    const { page, limit } = req.pagination;

    const result = await Event.getAllPaginated(page, limit);

    // Transform participants data to match expected format
    const events = result.events.map(event => ({
      ...event,
      participants: event.participants.map(p => ({
        _id: p.userId,
        name: p.name,
        profilePicture: p.profilePicture
      }))
    }));

    res.json(buildPaginatedResponse(events, result.pagination.totalCount, page, limit));
  }),
);

// Create an event
router.post(
  "/",
  auth,
  createEventValidation,
  asyncHandler(async (req, res) => {
    const { title, description, date, location } = req.body;

    const event = await Event.create({
      title,
      description,
      date,
      location,
    });

    // Invalidate events cache
    invalidateCacheByPattern('/api/events');

    // Emit SSE event for new event
    const sse = req.app.get("sse");
    if (sse) {
      sse.broadcastToTopic("events", "eventUpdate", {
        type: "new_event",
        event,
      });
    }

    res.json(event);
  }),
);

// RSVP to an event
router.put(
  "/rsvp/:id",
  auth,
  eventIdValidation,
  asyncHandler(async (req, res) => {
    const eventId = req.params.id;
    const userId = req.user.id;

    // Check if event exists
    const event = await Event.findById(eventId);
    if (!event) {
      return res.status(404).json({ msg: "Event not found" });
    }

    // Check if user has already RSVPed
    const alreadyParticipating = event.participants.some(p => p.userId === userId);
    if (alreadyParticipating) {
      return res.status(400).json({ msg: "Already RSVPed" });
    }

    // Get user data for embedding
    const user = await User.findById(userId);
    if (!user) {
      return res.status(404).json({ msg: "User not found" });
    }

    // Add participant to event
    const updatedEvent = await Event.addParticipant(
      eventId,
      userId,
      user.name,
      user.profilePicture
    );

    // Update user's events array
    if (!user.events.includes(eventId)) {
      user.events.push(eventId);
      user.stats.eventsParticipated = user.events.length;
      if (typeof user.save === 'function') {
        await user.save();
      } else if (typeof User.update === 'function') {
        await User.update(userId, { events: user.events, stats: user.stats });
      }
    }

    // Award points for event participation using couchdbService
    const updatedUser = await couchdbService.updateUserPoints(
      userId,
      15,
      `Joined event: ${event.title}`,
      {
        entityType: 'Event',
        entityId: eventId,
        entityName: event.title
      }
    );

    // Check and award badges
    await couchdbService.checkAndAwardBadges(userId, updatedUser.points);

    // Emit SSE event for RSVP
    const sse = req.app.get("sse");
    if (sse) {
      sse.broadcastToTopic(`event_${eventId}`, "eventUpdate", {
        type: "participants_updated",
        eventId,
        participants: updatedEvent.participants,
      });
    }

    res.json({
      participants: updatedEvent.participants,
      pointsAwarded: 15,
      newBalance: updatedUser.points,
    });
  }),
);

// Get event by ID
router.get(
  "/:id",
  eventIdValidation,
  asyncHandler(async (req, res) => {
    const event = await Event.findById(req.params.id);
    if (!event) {
      return res.status(404).json({ msg: "Event not found" });
    }

    // Transform participants data to match expected format
    const transformedEvent = {
      ...event,
      participants: event.participants.map(p => ({
        _id: p.userId,
        name: p.name,
        profilePicture: p.profilePicture
      }))
    };

    res.json(transformedEvent);
  })
);

// Update event
router.put(
  "/:id",
  auth,
  eventIdValidation,
  createEventValidation,
  asyncHandler(async (req, res) => {
    const { title, description, date, location, status } = req.body;
    
    const event = await Event.findById(req.params.id);
    if (!event) {
      return res.status(404).json({ msg: "Event not found" });
    }

    const updateData = { title, description, date, location };
    if (status) {
      updateData.status = status;
    }

    const updatedEvent = await Event.update(req.params.id, updateData);

    // Emit SSE event for event update
    const sse = req.app.get("sse");
    if (sse) {
      sse.broadcastToTopic(`event_${req.params.id}`, "eventUpdate", {
        type: "event_updated",
        event: updatedEvent,
      });
    }

    res.json(updatedEvent);
  })
);

// Update event status
router.patch(
  "/:id/status",
  auth,
  eventIdValidation,
  asyncHandler(async (req, res) => {
    const { status } = req.body;
    
    if (!["upcoming", "ongoing", "completed", "cancelled"].includes(status)) {
      return res.status(400).json({ msg: "Invalid status" });
    }

    const updatedEvent = await Event.updateStatus(req.params.id, status);
    res.json(updatedEvent);
  })
);

// Cancel RSVP
router.delete(
  "/rsvp/:id",
  auth,
  eventIdValidation,
  asyncHandler(async (req, res) => {
    const eventId = req.params.id;
    const userId = req.user.id;

    // Check if event exists
    const event = await Event.findById(eventId);
    if (!event) {
      return res.status(404).json({ msg: "Event not found" });
    }

    // Check if user is participating
    const isParticipating = event.participants.some(p => p.userId === userId);
    if (!isParticipating) {
      return res.status(400).json({ msg: "Not participating in this event" });
    }

    // Remove participant from event
    const updatedEvent = await Event.removeParticipant(eventId, userId);

    // Update user's events array
    const user = await User.findById(userId);
    if (user) {
      user.events = user.events.filter(id => id !== eventId);
      user.stats.eventsParticipated = user.events.length;
      await user.save();
    }

    res.json({
      participants: updatedEvent.participants,
      msg: "RSVP cancelled successfully"
    });
  })
);

// Delete event
router.delete(
  "/:id",
  auth,
  eventIdValidation,
  asyncHandler(async (req, res) => {
    const event = await Event.findById(req.params.id);
    if (!event) {
      return res.status(404).json({ msg: "Event not found" });
    }

    await Event.delete(req.params.id);

    // Emit SSE event for event deletion
    const sse = req.app.get("sse");
    if (sse) {
      sse.broadcastToTopic(`event_${req.params.id}`, "eventUpdate", {
        type: "event_deleted",
        eventId: req.params.id,
      });
    }

    res.json({ msg: "Event deleted successfully" });
  })
);

// Get upcoming events
router.get(
  "/upcoming/list",
  asyncHandler(async (req, res) => {
    const { limit = 10 } = req.query;
    const events = await Event.getUpcomingEvents(parseInt(limit));
    
    // Transform participants data
    const transformedEvents = events.map(event => ({
      ...event,
      participants: event.participants.map(p => ({
        _id: p.userId,
        name: p.name,
        profilePicture: p.profilePicture
      }))
    }));

    res.json(transformedEvents);
  })
);

// Get events by status
router.get(
  "/status/:status",
  asyncHandler(async (req, res) => {
    const { status } = req.params;

    if (!["upcoming", "ongoing", "completed", "cancelled"].includes(status)) {
      return res.status(400).json({ msg: "Invalid status" });
    }

    const events = await Event.findByStatus(status);
    
    // Transform participants data
    const transformedEvents = events.map(event => ({
      ...event,
      participants: event.participants.map(p => ({
        _id: p.userId,
        name: p.name,
        profilePicture: p.profilePicture
      }))
    }));

    res.json(transformedEvents);
  })
);

// Get user's events
router.get(
  "/user/:userId",
  auth,
  asyncHandler(async (req, res) => {
    const { userId } = req.params;
    const events = await Event.getEventsByUser(userId);
    
    // Transform participants data
    const transformedEvents = events.map(event => ({
      ...event,
      participants: event.participants.map(p => ({
        _id: p.userId,
        name: p.name,
        profilePicture: p.profilePicture
      }))
    }));

    res.json(transformedEvents);
  })
);

module.exports = router;
