import { Request, Response } from 'express';
import eventsService from '../services/events.service';
import {
  CreateKategorieSchema,
  UpdateKategorieSchema,
  CreateVeranstaltungSchema,
  UpdateVeranstaltungSchema,
  CancelVeranstaltungSchema,
} from '../models/events.model';
import logger from '../utils/logger';

// ---------------------------------------------------------------------------
// Helper — extract userGroups from request
// ---------------------------------------------------------------------------

function getUserGroups(req: Request): string[] {
  return (req.user as any)?.groups ?? [];
}

// ---------------------------------------------------------------------------
// Controller
// ---------------------------------------------------------------------------

class EventsController {
  // -------------------------------------------------------------------------
  // GET /api/events/kategorien
  // -------------------------------------------------------------------------
  listKategorien = async (_req: Request, res: Response): Promise<void> => {
    try {
      const data = await eventsService.getKategorien();
      res.json({ success: true, data });
    } catch (error) {
      logger.error('listKategorien error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Kategorien' });
    }
  };

  // -------------------------------------------------------------------------
  // POST /api/events/kategorien
  // -------------------------------------------------------------------------
  createKategorie = async (req: Request, res: Response): Promise<void> => {
    try {
      const parsed = CreateKategorieSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({
          success: false,
          message: 'Validierungsfehler',
          errors: parsed.error.flatten().fieldErrors,
        });
        return;
      }
      const data = await eventsService.createKategorie(parsed.data, req.user!.id);
      res.status(201).json({ success: true, data });
    } catch (error) {
      logger.error('createKategorie error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Erstellen der Kategorie' });
    }
  };

  // -------------------------------------------------------------------------
  // PATCH /api/events/kategorien/:id
  // -------------------------------------------------------------------------
  updateKategorie = async (req: Request, res: Response): Promise<void> => {
    try {
      const { id } = req.params as Record<string, string>;
      const parsed = UpdateKategorieSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({
          success: false,
          message: 'Validierungsfehler',
          errors: parsed.error.flatten().fieldErrors,
        });
        return;
      }
      const data = await eventsService.updateKategorie(id, parsed.data);
      if (!data) {
        res.status(404).json({ success: false, message: 'Kategorie nicht gefunden' });
        return;
      }
      res.json({ success: true, data });
    } catch (error) {
      logger.error('updateKategorie error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Aktualisieren der Kategorie' });
    }
  };

  // -------------------------------------------------------------------------
  // DELETE /api/events/kategorien/:id
  // -------------------------------------------------------------------------
  deleteKategorie = async (req: Request, res: Response): Promise<void> => {
    try {
      const { id } = req.params as Record<string, string>;
      await eventsService.deleteKategorie(id);
      res.json({ success: true, message: 'Kategorie wurde gelöscht' });
    } catch (error: any) {
      if (
        error.message === 'Kategorie nicht gefunden' ||
        error.message?.includes('noch Veranstaltungen')
      ) {
        res.status(409).json({ success: false, message: error.message });
        return;
      }
      logger.error('deleteKategorie error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Löschen der Kategorie' });
    }
  };

  // -------------------------------------------------------------------------
  // GET /api/events/groups
  // -------------------------------------------------------------------------
  getAvailableGroups = async (_req: Request, res: Response): Promise<void> => {
    try {
      const groups = await eventsService.getAvailableGroups();
      res.json({ success: true, data: groups });
    } catch (error) {
      logger.error('getAvailableGroups error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Gruppen' });
    }
  };

  // -------------------------------------------------------------------------
  // GET /api/events/conflicts?from=<ISO>&to=<ISO>&excludeId=<uuid>
  // -------------------------------------------------------------------------
  checkConflicts = async (req: Request, res: Response): Promise<void> => {
    try {
      const fromStr = req.query.from as string | undefined;
      const toStr = req.query.to as string | undefined;
      const excludeId = req.query.excludeId as string | undefined;

      if (!fromStr || !toStr) {
        res.status(400).json({
          success: false,
          message: 'Query-Parameter "from" und "to" sind erforderlich (ISO-8601)',
        });
        return;
      }

      const from = new Date(fromStr);
      const to = new Date(toStr);

      if (isNaN(from.getTime()) || isNaN(to.getTime())) {
        res.status(400).json({ success: false, message: 'Ungültiges Datumsformat' });
        return;
      }

      const data = await eventsService.checkConflicts(from, to, excludeId);
      res.json({ success: true, data });
    } catch (error) {
      logger.error('checkConflicts error', { error });
      res.status(500).json({ success: false, message: 'Fehler bei der Konfliktprüfung' });
    }
  };

  // -------------------------------------------------------------------------
  // GET /api/events/calendar?from=<ISO>&to=<ISO>
  // -------------------------------------------------------------------------
  getCalendarRange = async (req: Request, res: Response): Promise<void> => {
    try {
      const fromStr = req.query.from as string | undefined;
      const toStr   = req.query.to   as string | undefined;

      if (!fromStr || !toStr) {
        res.status(400).json({
          success: false,
          message: 'Query-Parameter "from" und "to" sind erforderlich (ISO-8601)',
        });
        return;
      }

      const from = new Date(fromStr);
      const to   = new Date(toStr);

      if (isNaN(from.getTime()) || isNaN(to.getTime())) {
        res.status(400).json({ success: false, message: 'Ungültiges Datumsformat' });
        return;
      }

      if (to < from) {
        res.status(400).json({ success: false, message: '"to" muss nach "from" liegen' });
        return;
      }

      const userGroups = getUserGroups(req);
      const data = await eventsService.getEventsByDateRange(from, to, userGroups);
      res.json({ success: true, data });
    } catch (error) {
      logger.error('getCalendarRange error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden des Kalenders' });
    }
  };

  // -------------------------------------------------------------------------
  // GET /api/events/upcoming?limit=10
  // -------------------------------------------------------------------------
  getUpcoming = async (req: Request, res: Response): Promise<void> => {
    try {
      const limit = Math.min(Number(req.query.limit) || 10, 50);
      const userGroups = getUserGroups(req);
      const data = await eventsService.getUpcomingEvents(limit, userGroups);
      res.json({ success: true, data });
    } catch (error) {
      logger.error('getUpcoming error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Veranstaltungen' });
    }
  };

  // -------------------------------------------------------------------------
  // GET /api/events/:id
  // -------------------------------------------------------------------------
  getById = async (req: Request, res: Response): Promise<void> => {
    try {
      const { id } = req.params as Record<string, string>;
      const event = await eventsService.getById(id);
      if (!event) {
        res.status(404).json({ success: false, message: 'Veranstaltung nicht gefunden' });
        return;
      }
      res.json({ success: true, data: event });
    } catch (error) {
      logger.error('getById error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Veranstaltung' });
    }
  };

  // -------------------------------------------------------------------------
  // POST /api/events
  // -------------------------------------------------------------------------
  createEvent = async (req: Request, res: Response): Promise<void> => {
    try {
      const parsed = CreateVeranstaltungSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({
          success: false,
          message: 'Validierungsfehler',
          errors: parsed.error.flatten().fieldErrors,
        });
        return;
      }
      const data = await eventsService.createEvent(parsed.data, req.user!.id);
      res.status(201).json({ success: true, data });
    } catch (error) {
      logger.error('createEvent error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Erstellen der Veranstaltung' });
    }
  };

  // -------------------------------------------------------------------------
  // PATCH /api/events/:id
  // -------------------------------------------------------------------------
  updateEvent = async (req: Request, res: Response): Promise<void> => {
    try {
      const { id } = req.params as Record<string, string>;
      const parsed = UpdateVeranstaltungSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({
          success: false,
          message: 'Validierungsfehler',
          errors: parsed.error.flatten().fieldErrors,
        });
        return;
      }
      const data = await eventsService.updateEvent(id, parsed.data);
      if (!data) {
        res.status(404).json({ success: false, message: 'Veranstaltung nicht gefunden' });
        return;
      }
      res.json({ success: true, data });
    } catch (error) {
      logger.error('updateEvent error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Aktualisieren der Veranstaltung' });
    }
  };

  // -------------------------------------------------------------------------
  // DELETE /api/events/:id  (soft cancel)
  // -------------------------------------------------------------------------
  cancelEvent = async (req: Request, res: Response): Promise<void> => {
    try {
      const { id } = req.params as Record<string, string>;
      const parsed = CancelVeranstaltungSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({
          success: false,
          message: 'Validierungsfehler',
          errors: parsed.error.flatten().fieldErrors,
        });
        return;
      }
      await eventsService.cancelEvent(id, parsed.data.abgesagt_grund, req.user!.id);
      res.json({ success: true, message: 'Veranstaltung wurde abgesagt' });
    } catch (error: any) {
      if (error.message === 'Event not found') {
        res.status(404).json({ success: false, message: 'Veranstaltung nicht gefunden' });
        return;
      }
      logger.error('cancelEvent error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Absagen der Veranstaltung' });
    }
  };

  // -------------------------------------------------------------------------
  // POST /api/events/:id/delete  (hard delete)
  // -------------------------------------------------------------------------
  deleteEvent = async (req: Request, res: Response): Promise<void> => {
    try {
      const { id } = req.params as Record<string, string>;
      const mode = (req.body?.mode as string) || 'all';
      if (!['all', 'single', 'future'].includes(mode)) {
        res.status(400).json({ success: false, message: 'Ungültiger Löschmodus. Erlaubt: all, single, future' });
        return;
      }
      const deleted = await eventsService.deleteEvent(id, mode as 'all' | 'single' | 'future');
      if (!deleted) {
        res.status(404).json({ success: false, message: 'Veranstaltung nicht gefunden' });
        return;
      }
      res.json({ success: true, message: 'Veranstaltung wurde gelöscht' });
    } catch (error) {
      logger.error('deleteEvent error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Löschen der Veranstaltung' });
    }
  };

  // -------------------------------------------------------------------------
  // GET /api/events/calendar-token
  // -------------------------------------------------------------------------
  getCalendarToken = async (req: Request, res: Response): Promise<void> => {
    try {
      if (!req.user) {
        res.status(401).json({ success: false, message: 'Nicht authentifiziert' });
        return;
      }
      const data = await eventsService.getOrCreateIcalToken(req.user.id);
      res.json({ success: true, data });
    } catch (error) {
      logger.error('getCalendarToken error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden des Kalender-Tokens' });
    }
  };

  // -------------------------------------------------------------------------
  // GET /api/events/calendar.ics?token=<token>
  // -------------------------------------------------------------------------
  getIcalExport = async (req: Request, res: Response): Promise<void> => {
    try {
      const token = req.query.token as string | undefined;
      if (!token) {
        res.status(400).send('Token required');
        return;
      }
      const ical = await eventsService.getIcalExport(token);
      if (!ical) {
        res.status(404).send('Invalid token');
        return;
      }
      res.setHeader('Content-Type', 'text/calendar; charset=utf-8');
      res.setHeader('Content-Disposition', 'attachment; filename="veranstaltungen.ics"');
      // 30-minute cache — calendar clients typically re-fetch at this interval
      res.setHeader('Cache-Control', 'max-age=1800, public');
      res.send(ical);
    } catch (error) {
      logger.error('getIcalExport error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Erstellen des Kalender-Exports' });
    }
  };
  // -------------------------------------------------------------------------
  // POST /api/events/import
  // -------------------------------------------------------------------------
  importEvents = async (req: Request, res: Response): Promise<void> => {
    try {
      const { events } = req.body as { events: unknown[] };
      if (!Array.isArray(events) || events.length === 0) {
        res.status(400).json({ success: false, message: 'Keine Ereignisse zum Importieren' });
        return;
      }
      const userId = (req.user as any)?.id ?? 'unknown';
      const created: number[] = [];
      const errors: string[] = [];

      for (let i = 0; i < events.length; i++) {
        try {
          const parsed = CreateVeranstaltungSchema.safeParse(events[i]);
          if (!parsed.success) {
            errors.push(`Zeile ${i + 2}: ${parsed.error.issues.map((e) => e.message).join(', ')}`);
            continue;
          }
          await eventsService.createEvent(parsed.data, userId);
          created.push(i);
        } catch (e) {
          errors.push(`Zeile ${i + 2}: ${e instanceof Error ? e.message : 'Unbekannter Fehler'}`);
        }
      }

      res.status(200).json({
        success: true,
        data: { created: created.length, errors },
      });
    } catch (error) {
      logger.error('importEvents error', { error });
      res.status(500).json({ success: false, message: 'Import fehlgeschlagen' });
    }
  };
}

export default new EventsController();
