import { Request, Response } from 'express';
import incidentService from '../services/incident.service';
import logger from '../utils/logger';
import { AppError } from '../middleware/error.middleware';
import { AppRole } from '../middleware/rbac.middleware';
import { permissionService } from '../services/permission.service';
import {
  CreateEinsatzSchema,
  UpdateEinsatzSchema,
  AssignPersonnelSchema,
  AssignVehicleSchema,
  IncidentFiltersSchema,
} from '../models/incident.model';

// Extend Request type to carry the resolved role (set by requirePermission)
interface AuthenticatedRequest extends Request {
  userRole?: AppRole;
}

class IncidentController {
  // -------------------------------------------------------------------------
  // GET /api/incidents
  // -------------------------------------------------------------------------
  async listIncidents(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const parseResult = IncidentFiltersSchema.safeParse(req.query);
      if (!parseResult.success) {
        res.status(400).json({
          success: false,
          message: 'Ungültige Filter-Parameter',
          errors: parseResult.error.issues,
        });
        return;
      }

      const { items, total } = await incidentService.getAllIncidents(parseResult.data);

      res.status(200).json({
        success: true,
        data: {
          items,
          total,
          limit: parseResult.data.limit,
          offset: parseResult.data.offset,
        },
      });
    } catch (error) {
      logger.error('List incidents error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Einsätze' });
    }
  }

  // -------------------------------------------------------------------------
  // GET /api/incidents/stats
  // -------------------------------------------------------------------------
  async getStats(req: Request, res: Response): Promise<void> {
    try {
      const year = req.query.year ? parseInt(req.query.year as string, 10) : undefined;

      if (year !== undefined && (isNaN(year) || year < 2000 || year > 2100)) {
        res.status(400).json({ success: false, message: 'Ungültiges Jahr' });
        return;
      }

      const stats = await incidentService.getIncidentStats(year);
      res.status(200).json({ success: true, data: stats });
    } catch (error) {
      logger.error('Get incident stats error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Statistik' });
    }
  }

  // -------------------------------------------------------------------------
  // GET /api/incidents/:id
  // -------------------------------------------------------------------------
  async getIncident(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const { id } = req.params as Record<string, string>;

      // UUID validation
      if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)) {
        res.status(400).json({ success: false, message: 'Ungültige Einsatz-ID' });
        return;
      }

      const incident = await incidentService.getIncidentById(id);

      if (!incident) {
        throw new AppError('Einsatz nicht gefunden', 404);
      }

      // Role-based redaction: check einsaetze:view_reports permission
      const groups: string[] = req.user?.groups ?? [];
      const canReadBerichtText =
        groups.includes('dashboard_admin') ||
        permissionService.hasPermission(groups, 'einsaetze:view_reports');

      const responseData = {
        ...incident,
        bericht_text: canReadBerichtText ? incident.bericht_text : undefined,
      };

      res.status(200).json({ success: true, data: responseData });
    } catch (error) {
      if (error instanceof AppError) {
        res.status(error.statusCode).json({ success: false, message: error.message });
        return;
      }
      logger.error('Get incident error', { error, id: req.params.id });
      res.status(500).json({ success: false, message: 'Fehler beim Laden des Einsatzes' });
    }
  }

  // -------------------------------------------------------------------------
  // POST /api/incidents
  // -------------------------------------------------------------------------
  async createIncident(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      if (!req.user) {
        res.status(401).json({ success: false, message: 'Nicht authentifiziert' });
        return;
      }

      const parseResult = CreateEinsatzSchema.safeParse(req.body);
      if (!parseResult.success) {
        res.status(400).json({
          success: false,
          message: 'Validierungsfehler',
          errors: parseResult.error.issues,
        });
        return;
      }

      const einsatz = await incidentService.createIncident(parseResult.data, req.user.id);

      logger.info('Incident created via API', {
        einsatzId: einsatz.id,
        einsatz_nr: einsatz.einsatz_nr,
        createdBy: req.user.id,
      });

      res.status(201).json({ success: true, data: einsatz });
    } catch (error) {
      logger.error('Create incident error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Erstellen des Einsatzes' });
    }
  }

  // -------------------------------------------------------------------------
  // PATCH /api/incidents/:id
  // -------------------------------------------------------------------------
  async updateIncident(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      if (!req.user) {
        res.status(401).json({ success: false, message: 'Nicht authentifiziert' });
        return;
      }

      const { id } = req.params as Record<string, string>;
      const parseResult = UpdateEinsatzSchema.safeParse(req.body);
      if (!parseResult.success) {
        res.status(400).json({
          success: false,
          message: 'Validierungsfehler',
          errors: parseResult.error.issues,
        });
        return;
      }

      const einsatz = await incidentService.updateIncident(id, parseResult.data, req.user.id);

      res.status(200).json({ success: true, data: einsatz });
    } catch (error) {
      if (error instanceof Error && error.message === 'Incident not found') {
        res.status(404).json({ success: false, message: 'Einsatz nicht gefunden' });
        return;
      }
      logger.error('Update incident error', { error, id: req.params.id });
      res.status(500).json({ success: false, message: 'Fehler beim Aktualisieren des Einsatzes' });
    }
  }

  // -------------------------------------------------------------------------
  // DELETE /api/incidents/:id  (soft delete)
  // -------------------------------------------------------------------------
  async deleteIncident(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      if (!req.user) {
        res.status(401).json({ success: false, message: 'Nicht authentifiziert' });
        return;
      }

      const { id } = req.params as Record<string, string>;
      await incidentService.deleteIncident(id, req.user.id);

      res.status(200).json({ success: true, message: 'Einsatz archiviert' });
    } catch (error) {
      if (error instanceof Error && error.message.includes('not found')) {
        res.status(404).json({ success: false, message: 'Einsatz nicht gefunden' });
        return;
      }
      logger.error('Delete incident error', { error, id: req.params.id });
      res.status(500).json({ success: false, message: 'Fehler beim Archivieren des Einsatzes' });
    }
  }

  // -------------------------------------------------------------------------
  // POST /api/incidents/:id/personnel
  // -------------------------------------------------------------------------
  async assignPersonnel(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const { id } = req.params as Record<string, string>;

      const parseResult = AssignPersonnelSchema.safeParse(req.body);
      if (!parseResult.success) {
        res.status(400).json({
          success: false,
          message: 'Validierungsfehler',
          errors: parseResult.error.issues,
        });
        return;
      }

      await incidentService.assignPersonnel(id, parseResult.data);

      res.status(200).json({ success: true, message: 'Person zugewiesen' });
    } catch (error) {
      logger.error('Assign personnel error', { error, id: req.params.id });
      res.status(500).json({ success: false, message: 'Fehler beim Zuweisen der Person' });
    }
  }

  // -------------------------------------------------------------------------
  // DELETE /api/incidents/:id/personnel/:userId
  // -------------------------------------------------------------------------
  async removePersonnel(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const { id, userId } = req.params as Record<string, string>;
      await incidentService.removePersonnel(id, userId);

      res.status(200).json({ success: true, message: 'Person entfernt' });
    } catch (error) {
      if (error instanceof Error && error.message.includes('not found')) {
        res.status(404).json({ success: false, message: 'Zuweisung nicht gefunden' });
        return;
      }
      logger.error('Remove personnel error', { error, id: req.params.id });
      res.status(500).json({ success: false, message: 'Fehler beim Entfernen der Person' });
    }
  }

  // -------------------------------------------------------------------------
  // POST /api/incidents/:id/vehicles
  // -------------------------------------------------------------------------
  async assignVehicle(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const { id } = req.params as Record<string, string>;

      const parseResult = AssignVehicleSchema.safeParse(req.body);
      if (!parseResult.success) {
        res.status(400).json({
          success: false,
          message: 'Validierungsfehler',
          errors: parseResult.error.issues,
        });
        return;
      }

      await incidentService.assignVehicle(id, parseResult.data);

      res.status(200).json({ success: true, message: 'Fahrzeug zugewiesen' });
    } catch (error) {
      logger.error('Assign vehicle error', { error, id: req.params.id });
      res.status(500).json({ success: false, message: 'Fehler beim Zuweisen des Fahrzeugs' });
    }
  }

  // -------------------------------------------------------------------------
  // DELETE /api/incidents/:id/vehicles/:fahrzeugId
  // -------------------------------------------------------------------------
  async removeVehicle(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const { id, fahrzeugId } = req.params as Record<string, string>;
      await incidentService.removeVehicle(id, fahrzeugId);

      res.status(200).json({ success: true, message: 'Fahrzeug entfernt' });
    } catch (error) {
      if (error instanceof Error && error.message.includes('not found')) {
        res.status(404).json({ success: false, message: 'Zuweisung nicht gefunden' });
        return;
      }
      logger.error('Remove vehicle error', { error, id: req.params.id });
      res.status(500).json({ success: false, message: 'Fehler beim Entfernen des Fahrzeugs' });
    }
  }

  // -------------------------------------------------------------------------
  // POST /api/incidents/refresh-stats  (admin utility)
  // -------------------------------------------------------------------------
  async refreshStats(_req: Request, res: Response): Promise<void> {
    try {
      await incidentService.refreshStatistikView();
      res.status(200).json({ success: true, message: 'Statistik-View aktualisiert' });
    } catch (error) {
      logger.error('Refresh stats view error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Aktualisieren der Statistik' });
    }
  }
}

export default new IncidentController();
