import { Response } from 'express';
import * as contractTaskService from '../services/contractTask.service.js';
import * as contractService from '../services/contract.service.js';
import * as customerService from '../services/customer.service.js';
import * as appSettingService from '../services/appSetting.service.js';
import { logChange } from '../services/audit.service.js';
import { ApiResponse, AuthRequest } from '../types/index.js';
import { canAccessContract, getPortalAllowedCustomerIds } from '../utils/accessControl.js';

// ==================== ALL TASKS (Dashboard & Task List) ====================

export async function getAllTasks(req: AuthRequest, res: Response): Promise<void> {
  try {
    const { status, customerId } = req.query;
    const customerIdNum = customerId ? parseInt(customerId as string) : undefined;

    // Für Kundenportal: Filter auf erlaubte Kunden (mit Live-Vollmacht-Check)
    const allowedIds = await getPortalAllowedCustomerIds(req);
    let customerPortalCustomerIds: number[] | undefined;
    let customerPortalEmails: string[] | undefined;

    if (allowedIds) {
      // Wenn der Portal-User explizit nach einer customerId filtert, die er
      // nicht (mehr) vertreten darf → 403 statt 200 mit leerem Array
      // (Pentest Runde 10 – LOW: konsistentes Response-Verhalten nach
      // Vollmacht-Widerruf).
      if (customerIdNum !== undefined && !allowedIds.includes(customerIdNum)) {
        res.status(403).json({ success: false, error: 'Kein Zugriff auf diese Kundendaten' } as ApiResponse);
        return;
      }
      customerPortalCustomerIds = allowedIds;
      const customers = await customerService.getCustomersByIds(customerPortalCustomerIds);
      customerPortalEmails = customers
        .map((c: { id: number; portalEmail: string | null }) => c.portalEmail)
        .filter((email: string | null): email is string => !!email);
    }

    const tasks = await contractTaskService.getAllTasks({
      status: status as 'OPEN' | 'COMPLETED' | undefined,
      customerId: customerIdNum,
      customerPortalCustomerIds,
      customerPortalEmails,
    });

    res.json({ success: true, data: tasks } as ApiResponse);
  } catch (error) {
    res.status(500).json({
      success: false,
      error: 'Fehler beim Laden der Aufgaben',
    } as ApiResponse);
  }
}

export async function getTaskStats(req: AuthRequest, res: Response): Promise<void> {
  try {
    // Für Kundenportal: Filter auf erlaubte Kunden (mit Live-Vollmacht-Check)
    const allowedIds = await getPortalAllowedCustomerIds(req);
    let customerPortalCustomerIds: number[] | undefined;
    let customerPortalEmails: string[] | undefined;

    if (allowedIds) {
      customerPortalCustomerIds = allowedIds;
      const customers = await customerService.getCustomersByIds(customerPortalCustomerIds);
      customerPortalEmails = customers
        .map((c: { id: number; portalEmail: string | null }) => c.portalEmail)
        .filter((email: string | null): email is string => !!email);
    }

    const stats = await contractTaskService.getTaskStats({
      customerPortalCustomerIds,
      customerPortalEmails,
    });

    res.json({ success: true, data: stats } as ApiResponse);
  } catch (error) {
    res.status(500).json({
      success: false,
      error: 'Fehler beim Laden der Statistik',
    } as ApiResponse);
  }
}

// ==================== TASKS BY CONTRACT ====================

export async function getTasks(req: AuthRequest, res: Response): Promise<void> {
  try {
    const contractId = parseInt(req.params.contractId);
    const { status } = req.query;

    // Zentraler canAccessContract-Check inkl. Live-Vollmacht-Prüfung über
    // hasAuthorization (Pentest Runde 6 – HOCH-04: widerrufene Vollmachten
    // hatten vorher weiter Zugriff, weil nur representedCustomerIds-Array
    // konsultiert wurde, ohne Status-Check).
    if (!(await canAccessContract(req, res, contractId))) return;

    // Für Kundenportal-Benutzer: Lade E-Mails der erlaubten Kunden (mit Live-Vollmacht-Check)
    let customerPortalEmails: string[] | undefined;
    const allowedIds = await getPortalAllowedCustomerIds(req);
    if (allowedIds) {
      const customers = await customerService.getCustomersByIds(allowedIds);
      customerPortalEmails = customers
        .map((c: { id: number; portalEmail: string | null }) => c.portalEmail)
        .filter((email: string | null): email is string => !!email);
    }

    const tasks = await contractTaskService.getTasksByContract({
      contractId,
      status: status as 'OPEN' | 'COMPLETED' | undefined,
      customerPortalEmails,
    });

    res.json({ success: true, data: tasks } as ApiResponse);
  } catch (error) {
    res.status(500).json({
      success: false,
      error: 'Fehler beim Laden der Aufgaben',
    } as ApiResponse);
  }
}

// Allgemeine Aufgabe OHNE Vertrag/Kunde (nur Mitarbeiter/Admin). Ohne Vertrag
// gibt es keinen Kunden → visibleInPortal ist hier bedeutungslos und immer
// false (der Service erzwingt das ohnehin).
export async function createGeneralTask(req: AuthRequest, res: Response): Promise<void> {
  try {
    if (req.user?.isCustomerPortal) {
      res.status(403).json({ success: false, error: 'Kein Zugriff' } as ApiResponse);
      return;
    }
    const { title, description } = req.body ?? {};
    if (!title || !String(title).trim()) {
      res.status(400).json({ success: false, error: 'Titel ist erforderlich' } as ApiResponse);
      return;
    }
    const task = await contractTaskService.createTask({
      contractId: null,
      title: String(title).trim(),
      description,
      visibleInPortal: false,
      createdBy: req.user?.email,
    });
    await logChange({
      req, action: 'CREATE', resourceType: 'ContractTask',
      resourceId: task.id.toString(),
      label: `Allgemeine Aufgabe "${String(title).trim()}" erstellt (ohne Vertrag)`,
    });
    res.status(201).json({ success: true, data: task } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Aufgabe',
    } as ApiResponse);
  }
}

export async function createTask(req: AuthRequest, res: Response): Promise<void> {
  try {
    const contractId = parseInt(req.params.contractId);
    const { title, description, visibleInPortal } = req.body;

    if (!title) {
      res.status(400).json({
        success: false,
        error: 'Titel ist erforderlich',
      } as ApiResponse);
      return;
    }

    const createdBy = req.user?.email;

    // Für Kundenportal-Benutzer: visibleInPortal wird automatisch auf true gesetzt
    const finalVisibleInPortal = req.user?.isCustomerPortal ? true : visibleInPortal;

    const task = await contractTaskService.createTask({
      contractId,
      title,
      description,
      visibleInPortal: finalVisibleInPortal,
      createdBy,
    });

    await logChange({
      req, action: 'CREATE', resourceType: 'ContractTask',
      resourceId: task.id.toString(),
      label: `Aufgabe "${title}" erstellt`,
    });

    res.status(201).json({ success: true, data: task } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Aufgabe',
    } as ApiResponse);
  }
}

// Für Kundenportal-Benutzer: Support-Anfrage erstellen (ohne contracts:update Permission)
export async function createSupportTicket(req: AuthRequest, res: Response): Promise<void> {
  try {
    // Prüfe ob Support-Tickets aktiviert sind
    const supportEnabled = await appSettingService.getSettingBool('customerSupportTicketsEnabled');
    if (!supportEnabled) {
      res.status(403).json({
        success: false,
        error: 'Support-Anfragen sind nicht aktiviert',
      } as ApiResponse);
      return;
    }

    const contractId = parseInt(req.params.contractId);
    const { title, description } = req.body;

    if (!title) {
      res.status(400).json({
        success: false,
        error: 'Titel ist erforderlich',
      } as ApiResponse);
      return;
    }

    // canAccessContract inkl. Live-Vollmacht-Prüfung (siehe getTasks).
    if (!(await canAccessContract(req, res, contractId))) return;

    const createdBy = req.user?.email;

    const task = await contractTaskService.createTask({
      contractId,
      title,
      description,
      visibleInPortal: true, // Immer sichtbar im Portal
      createdBy,
    });

    await logChange({
      req, action: 'CREATE', resourceType: 'ContractTask',
      resourceId: task.id.toString(),
      label: `Support-Anfrage "${title}" erstellt`,
    });

    res.status(201).json({ success: true, data: task } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Support-Anfrage',
    } as ApiResponse);
  }
}

export async function updateTask(req: AuthRequest, res: Response): Promise<void> {
  try {
    const taskId = parseInt(req.params.taskId);
    const { title, description, visibleInPortal } = req.body;

    const task = await contractTaskService.updateTask(taskId, {
      title,
      description,
      visibleInPortal,
    });

    await logChange({
      req, action: 'UPDATE', resourceType: 'ContractTask',
      resourceId: taskId.toString(),
      label: `Aufgabe aktualisiert`,
    });

    res.json({ success: true, data: task } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Aufgabe',
    } as ApiResponse);
  }
}

export async function completeTask(req: AuthRequest, res: Response): Promise<void> {
  try {
    const taskId = parseInt(req.params.taskId);
    const task = await contractTaskService.completeTask(taskId);
    await logChange({
      req, action: 'UPDATE', resourceType: 'ContractTask',
      resourceId: taskId.toString(),
      label: `Aufgabe abgeschlossen`,
    });
    res.json({ success: true, data: task } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Abschließen der Aufgabe',
    } as ApiResponse);
  }
}

export async function reopenTask(req: AuthRequest, res: Response): Promise<void> {
  try {
    const taskId = parseInt(req.params.taskId);
    const task = await contractTaskService.reopenTask(taskId);
    await logChange({
      req, action: 'UPDATE', resourceType: 'ContractTask',
      resourceId: taskId.toString(),
      label: `Aufgabe wiedereröffnet`,
    });
    res.json({ success: true, data: task } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Wiedereröffnen der Aufgabe',
    } as ApiResponse);
  }
}

export async function deleteTask(req: AuthRequest, res: Response): Promise<void> {
  try {
    const taskId = parseInt(req.params.taskId);
    await contractTaskService.deleteTask(taskId);
    await logChange({
      req, action: 'DELETE', resourceType: 'ContractTask',
      resourceId: taskId.toString(),
      label: `Aufgabe gelöscht`,
    });
    res.json({ success: true, message: 'Aufgabe gelöscht' } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Löschen der Aufgabe',
    } as ApiResponse);
  }
}

// ==================== SUBTASKS ====================

export async function createSubtask(req: AuthRequest, res: Response): Promise<void> {
  try {
    const taskId = parseInt(req.params.taskId);
    const { title } = req.body;

    if (!title) {
      res.status(400).json({
        success: false,
        error: 'Titel ist erforderlich',
      } as ApiResponse);
      return;
    }

    const createdBy = req.user?.email;

    const subtask = await contractTaskService.createSubtask({
      taskId,
      title,
      createdBy,
    });

    await logChange({
      req, action: 'CREATE', resourceType: 'ContractSubtask',
      resourceId: subtask.id.toString(),
      label: `Unteraufgabe "${title}" erstellt`,
    });

    res.status(201).json({ success: true, data: subtask } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Unteraufgabe',
    } as ApiResponse);
  }
}

// Kundenportal: Antwort auf eigenes Ticket erstellen
export async function createCustomerReply(req: AuthRequest, res: Response): Promise<void> {
  try {
    const taskId = parseInt(req.params.taskId);
    const { title } = req.body;

    if (!title) {
      res.status(400).json({
        success: false,
        error: 'Antwort ist erforderlich',
      } as ApiResponse);
      return;
    }

    // Hole den Task
    const task = await contractTaskService.getTaskById(taskId);
    if (!task) {
      res.status(404).json({
        success: false,
        error: 'Anfrage nicht gefunden',
      } as ApiResponse);
      return;
    }

    if (!req.user?.isCustomerPortal || !req.user.customerId) {
      res.status(403).json({
        success: false,
        error: 'Nur für Kundenportal-Benutzer',
      } as ApiResponse);
      return;
    }

    // Allgemeine Aufgaben (ohne Vertrag/Kunde) sind reine Mitarbeiter-Aufgaben
    // und für Portal-User nie zugänglich.
    if (task.contractId == null) {
      res.status(403).json({ success: false, error: 'Kein Zugriff' } as ApiResponse);
      return;
    }
    // Strikter Owner-Check über den Vertrag (mit Live-Vollmacht-Prüfung
    // via hasAuthorization, Pentest Runde 6 – HOCH-04). Damit kann ein
    // Portal-User keine fremde Task-ID mit visibleInPortal=true abgreifen.
    if (!(await canAccessContract(req, res, task.contractId))) return;

    // Zusätzlich: portal-User darf nur antworten, wenn die Task von ihm
    // initiiert wurde ODER explizit für ihn sichtbar markiert ist.
    const allowedCustomerIds = [req.user.customerId, ...(req.user.representedCustomerIds || [])];
    const customers = await customerService.getCustomersByIds(allowedCustomerIds);
    const allowedEmails = customers
      .map((c: { id: number; portalEmail: string | null }) => c.portalEmail)
      .filter((email: string | null): email is string => !!email);
    const isOwnTask = task.createdBy && allowedEmails.includes(task.createdBy);
    if (!task.visibleInPortal && !isOwnTask) {
      res.status(403).json({
        success: false,
        error: 'Kein Zugriff auf diese Anfrage',
      } as ApiResponse);
      return;
    }

    const createdBy = req.user?.email;

    const subtask = await contractTaskService.createSubtask({
      taskId,
      title,
      createdBy,
    });

    await logChange({
      req, action: 'CREATE', resourceType: 'ContractSubtask',
      resourceId: subtask.id.toString(),
      label: `Kundenantwort erstellt`,
    });

    res.status(201).json({ success: true, data: subtask } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Antwort',
    } as ApiResponse);
  }
}

export async function updateSubtask(req: AuthRequest, res: Response): Promise<void> {
  try {
    const subtaskId = parseInt(req.params.subtaskId);
    const { title } = req.body;

    if (!title) {
      res.status(400).json({
        success: false,
        error: 'Titel ist erforderlich',
      } as ApiResponse);
      return;
    }

    const subtask = await contractTaskService.updateSubtask(subtaskId, { title });
    await logChange({
      req, action: 'UPDATE', resourceType: 'ContractSubtask',
      resourceId: subtaskId.toString(),
      label: `Unteraufgabe aktualisiert`,
    });
    res.json({ success: true, data: subtask } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Unteraufgabe',
    } as ApiResponse);
  }
}

export async function completeSubtask(req: AuthRequest, res: Response): Promise<void> {
  try {
    const subtaskId = parseInt(req.params.subtaskId);
    const subtask = await contractTaskService.completeSubtask(subtaskId);
    await logChange({
      req, action: 'UPDATE', resourceType: 'ContractSubtask',
      resourceId: subtaskId.toString(),
      label: `Unteraufgabe abgeschlossen`,
    });
    res.json({ success: true, data: subtask } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Abschließen der Unteraufgabe',
    } as ApiResponse);
  }
}

export async function reopenSubtask(req: AuthRequest, res: Response): Promise<void> {
  try {
    const subtaskId = parseInt(req.params.subtaskId);
    const subtask = await contractTaskService.reopenSubtask(subtaskId);
    await logChange({
      req, action: 'UPDATE', resourceType: 'ContractSubtask',
      resourceId: subtaskId.toString(),
      label: `Unteraufgabe wiedereröffnet`,
    });
    res.json({ success: true, data: subtask } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Wiedereröffnen der Unteraufgabe',
    } as ApiResponse);
  }
}

export async function deleteSubtask(req: AuthRequest, res: Response): Promise<void> {
  try {
    const subtaskId = parseInt(req.params.subtaskId);
    await contractTaskService.deleteSubtask(subtaskId);
    await logChange({
      req, action: 'DELETE', resourceType: 'ContractSubtask',
      resourceId: subtaskId.toString(),
      label: `Unteraufgabe gelöscht`,
    });
    res.json({ success: true, message: 'Unteraufgabe gelöscht' } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Löschen der Unteraufgabe',
    } as ApiResponse);
  }
}
