import { Response } from "express";
import { CalendarEvent, RecurringDeleteMode } from "@calchat/shared";
import { EventService } from "../services";
import { createLogger } from "../logging";
import { AuthenticatedRequest } from "./AuthMiddleware";
import { CaldavService } from "../services/CaldavService";

const log = createLogger("EventController");

export class EventController {
  constructor(
    private eventService: EventService,
    private caldavService: CaldavService,
  ) {}

  private async pushToCaldav(userId: string, event: CalendarEvent) {
    if (await this.caldavService.getConfig(userId)) {
      try {
        await this.caldavService.pushEvent(userId, event);
      } catch (error) {
        log.error({ err: error, userId }, "Error pushing event to CalDAV");
      }
    }
  }

  private async deleteFromCaldav(userId: string, event: CalendarEvent) {
    if (event.caldavUUID && (await this.caldavService.getConfig(userId))) {
      try {
        await this.caldavService.deleteEvent(userId, event.caldavUUID);
      } catch (error) {
        log.error({ err: error, userId }, "Error deleting event from CalDAV");
      }
    }
  }

  async create(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const userId = req.user!.userId;
      const event = await this.eventService.create(userId, req.body);
      await this.pushToCaldav(userId, event);
      res.status(201).json(event);
    } catch (error) {
      log.error(
        { err: error, userId: req.user?.userId },
        "Error creating event",
      );
      res.status(500).json({ error: "Failed to create event" });
    }
  }

  async getById(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const event = await this.eventService.getById(
        req.params.id,
        req.user!.userId,
      );
      if (!event) {
        res.status(404).json({ error: "Event not found" });
        return;
      }
      res.json(event);
    } catch (error) {
      log.error({ err: error, eventId: req.params.id }, "Error getting event");
      res.status(500).json({ error: "Failed to get event" });
    }
  }

  async getAll(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const events = await this.eventService.getAll(req.user!.userId);
      res.json(events);
    } catch (error) {
      log.error(
        { err: error, userId: req.user?.userId },
        "Error getting events",
      );
      res.status(500).json({ error: "Failed to get events" });
    }
  }

  async getByDateRange(
    req: AuthenticatedRequest,
    res: Response,
  ): Promise<void> {
    try {
      const { start, end } = req.query;

      if (!start || !end) {
        res.status(400).json({ error: "start and end query params required" });
        return;
      }

      const startDate = new Date(start as string);
      const endDate = new Date(end as string);

      if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
        res.status(400).json({ error: "Invalid date format" });
        return;
      }

      const events = await this.eventService.getByDateRange(
        req.user!.userId,
        startDate,
        endDate,
      );
      res.json(events);
    } catch (error) {
      log.error(
        { err: error, start: req.query.start, end: req.query.end },
        "Error getting events by range",
      );
      res.status(500).json({ error: "Failed to get events" });
    }
  }

  async update(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const userId = req.user!.userId;
      const event = await this.eventService.update(
        req.params.id,
        userId,
        req.body,
      );
      if (!event) {
        res.status(404).json({ error: "Event not found" });
        return;
      }

      await this.pushToCaldav(userId, event);

      res.json(event);
    } catch (error) {
      log.error({ err: error, eventId: req.params.id }, "Error updating event");
      res.status(500).json({ error: "Failed to update event" });
    }
  }

  async delete(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const userId = req.user!.userId;
      const { mode, occurrenceDate } = req.query as {
        mode?: RecurringDeleteMode;
        occurrenceDate?: string;
      };

      // Fetch event before deletion to get caldavUUID for sync
      const event = await this.eventService.getById(req.params.id, userId);
      if (!event) {
        res.status(404).json({ error: "Event not found" });
        return;
      }

      // If mode is specified, use deleteRecurring
      if (mode) {
        const result = await this.eventService.deleteRecurring(
          req.params.id,
          userId,
          mode,
          occurrenceDate,
        );

        // Event was updated (single/future mode) - push update to CalDAV
        if (result) {
          await this.pushToCaldav(userId, result);
          res.json(result);
          return;
        }

        // Event was fully deleted (all mode, or future from first occurrence)
        await this.deleteFromCaldav(userId, event);
        res.status(204).send();
        return;
      }

      // Default behavior: delete completely
      await this.eventService.delete(req.params.id, userId);
      await this.deleteFromCaldav(userId, event);
      res.status(204).send();
    } catch (error) {
      log.error({ err: error, eventId: req.params.id }, "Error deleting event");
      res.status(500).json({ error: "Failed to delete event" });
    }
  }
}
