import { Request, Response, NextFunction } from 'express';
import { CalendarSyncService } from '../services/CalendarSyncService';
import { CalendarView } from '../views/EmbedView';

export class CalendarController {
  constructor(private calendarSyncService = new CalendarSyncService()) {}

  list = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const connections = await this.calendarSyncService.listConnections(req.userId!);
      res.json(CalendarView.toList(connections));
    } catch (err) {
      next(err);
    }
  };

  authorize = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const provider = req.params.provider as 'google' | 'microsoft';
      const url = this.calendarSyncService.getOAuthAuthorizeUrl(req.userId!, provider);
      res.redirect(url);
    } catch (err) {
      next(err);
    }
  };

  callback = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const provider = req.params.provider as 'google' | 'microsoft';
      const { code, state } = req.query as { code: string; state: string };
      const redirectUrl = await this.calendarSyncService.handleOAuthCallback(provider, code, state);
      res.redirect(redirectUrl);
    } catch (err) {
      next(err);
    }
  };

  connectApple = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const connection = await this.calendarSyncService.connectApple(
        req.userId!,
        req.body.appleId,
        req.body.appSpecificPassword,
      );
      res.status(201).json(CalendarView.toConnection(connection));
    } catch (err) {
      next(err);
    }
  };

  updateConfig = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const connection = await this.calendarSyncService.updateCalendarConfig(
        req.userId!,
        req.params.id,
        req.body.calendars,
      );
      res.json(CalendarView.toConnection(connection));
    } catch (err) {
      next(err);
    }
  };

  disconnect = async (req: Request, res: Response, next: NextFunction) => {
    try {
      await this.calendarSyncService.disconnect(req.userId!, req.params.id);
      res.status(204).send();
    } catch (err) {
      next(err);
    }
  };

  sync = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const connection = await this.calendarSyncService.syncConnection(req.userId!, req.params.id);
      res.json(CalendarView.toConnection(connection));
    } catch (err) {
      next(err);
    }
  };

  listEvents = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { from, to, calendarId } = req.query as {
        from: string;
        to: string;
        calendarId?: string;
      };
      const fromDate = new Date(from);
      const toDate = new Date(to);
      if (Number.isNaN(fromDate.getTime()) || Number.isNaN(toDate.getTime())) {
        res.status(400).json({ error: 'validation_error', message: 'Invalid from/to date.' });
        return;
      }
      const events = await this.calendarSyncService.listConnectionEvents(
        req.userId!,
        req.params.id,
        fromDate,
        toDate,
        calendarId,
      );
      res.json(CalendarView.toEvents(events));
    } catch (err) {
      next(err);
    }
  };
}
