import { Response } from 'express';
import { AuthRequest } from '../types/index.js';
import * as auditService from '../services/audit.service.js';
import { logChange } from '../services/audit.service.js';
import { AuditAction, AuditSensitivity } from '@prisma/client';

/**
 * Audit-Logs mit Filtern abrufen
 */
export async function getAuditLogs(req: AuthRequest, res: Response) {
  try {
    const {
      userId,
      customerId,
      dataSubjectId,
      action,
      sensitivity,
      resourceType,
      resourceId,
      startDate,
      endDate,
      success,
      search,
      page,
      limit,
    } = req.query;

    const result = await auditService.searchAuditLogs({
      userId: userId ? parseInt(userId as string) : undefined,
      customerId: customerId ? parseInt(customerId as string) : undefined,
      dataSubjectId: dataSubjectId ? parseInt(dataSubjectId as string) : undefined,
      action: action as AuditAction | undefined,
      sensitivity: sensitivity as AuditSensitivity | undefined,
      resourceType: resourceType as string | undefined,
      resourceId: resourceId as string | undefined,
      startDate: startDate ? new Date(startDate as string) : undefined,
      endDate: endDate ? new Date(endDate as string) : undefined,
      success: success !== undefined ? success === 'true' : undefined,
      search: search as string | undefined,
      page: page ? parseInt(page as string) : 1,
      limit: limit ? parseInt(limit as string) : 50,
    });

    res.json({ success: true, ...result });
  } catch (error) {
    console.error('Fehler beim Abrufen der Audit-Logs:', error);
    res.status(500).json({ success: false, error: 'Fehler beim Abrufen der Audit-Logs' });
  }
}

/**
 * Einzelnes Audit-Log abrufen
 */
export async function getAuditLogById(req: AuthRequest, res: Response) {
  try {
    const id = parseInt(req.params.id);
    // Nicht-numerische :id (z.B. GET /audit-logs/verify statt POST /verify)
    // landete sonst als NaN in Prisma findUnique → 500. Sauberer 400.
    // (Pentest R120 – gleiche „400 statt 500"-Klasse wie R64.1/R104.1.)
    if (Number.isNaN(id)) {
      return res.status(400).json({ success: false, error: 'Ungültige Audit-Log-ID' });
    }
    const log = await auditService.getAuditLogById(id);

    if (!log) {
      return res.status(404).json({ success: false, error: 'Audit-Log nicht gefunden' });
    }

    res.json({ success: true, data: log });
  } catch (error) {
    console.error('Fehler beim Abrufen des Audit-Logs:', error);
    res.status(500).json({ success: false, error: 'Fehler beim Abrufen des Audit-Logs' });
  }
}

/**
 * Audit-Logs für einen Kunden abrufen (DSGVO)
 */
export async function getAuditLogsByCustomer(req: AuthRequest, res: Response) {
  try {
    const customerId = parseInt(req.params.customerId);
    if (Number.isNaN(customerId)) {
      return res.status(400).json({ success: false, error: 'Ungültige Kunden-ID' });
    }
    const logs = await auditService.getAuditLogsByDataSubject(customerId);

    res.json({ success: true, data: logs });
  } catch (error) {
    console.error('Fehler beim Abrufen der Kunden-Audit-Logs:', error);
    res.status(500).json({ success: false, error: 'Fehler beim Abrufen der Audit-Logs' });
  }
}

/**
 * Audit-Logs exportieren
 */
export async function exportAuditLogs(req: AuthRequest, res: Response) {
  try {
    const format = (req.query.format as 'json' | 'csv') || 'json';
    const {
      action,
      sensitivity,
      resourceType,
      startDate,
      endDate,
    } = req.query;

    const content = await auditService.exportAuditLogs(
      {
        action: action as AuditAction | undefined,
        sensitivity: sensitivity as AuditSensitivity | undefined,
        resourceType: resourceType as string | undefined,
        startDate: startDate ? new Date(startDate as string) : undefined,
        endDate: endDate ? new Date(endDate as string) : undefined,
      },
      format
    );

    if (format === 'csv') {
      const filename = `audit-logs-${new Date().toISOString().split('T')[0]}.csv`;
      res.setHeader('Content-Type', 'text/csv; charset=utf-8');
      res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
      // BOM für Excel UTF-8 Erkennung
      res.send('\uFEFF' + content);
    } else {
      res.json({ success: true, data: JSON.parse(content) })
    }
  } catch (error) {
    console.error('Fehler beim Exportieren der Audit-Logs:', error);
    res.status(500).json({ success: false, error: 'Fehler beim Exportieren' });
  }
}

/**
 * Hash-Ketten-Integrität prüfen
 */
export async function verifyIntegrity(req: AuthRequest, res: Response) {
  try {
    const { fromId, toId } = req.query;

    const result = await auditService.verifyIntegrity(
      fromId ? parseInt(fromId as string) : undefined,
      toId ? parseInt(toId as string) : undefined
    );

    res.json({
      success: true,
      data: {
        valid: result.valid,
        checkedCount: result.checkedCount,
        invalidEntries: result.invalidEntries,
        message: result.valid
          ? 'Alle Einträge sind valide'
          : `${result.invalidEntries.length} manipulierte Einträge gefunden`,
      },
    });
  } catch (error) {
    console.error('Fehler bei der Integritätsprüfung:', error);
    res.status(500).json({ success: false, error: 'Fehler bei der Integritätsprüfung' });
  }
}

/**
 * Hash-Kette reparieren (alle Hashes neu berechnen)
 */
export async function rehashAll(req: AuthRequest, res: Response) {
  try {
    const result = await auditService.rehashAll();
    res.json({
      success: true,
      data: result,
      message: `${result.rehashedCount} Einträge neu gehasht. Kette ist jetzt intakt.`,
    });
  } catch (error) {
    console.error('Fehler beim Re-Hashing:', error);
    res.status(500).json({ success: false, error: 'Fehler beim Re-Hashing' });
  }
}

/**
 * Retention-Policies abrufen
 */
export async function getRetentionPolicies(req: AuthRequest, res: Response) {
  try {
    const policies = await auditService.getRetentionPolicies();
    res.json({ success: true, data: policies });
  } catch (error) {
    console.error('Fehler beim Abrufen der Retention-Policies:', error);
    res.status(500).json({ success: false, error: 'Fehler beim Abrufen der Policies' });
  }
}

/**
 * Retention-Policy aktualisieren
 */
export async function updateRetentionPolicy(req: AuthRequest, res: Response) {
  try {
    const id = parseInt(req.params.id);
    if (Number.isNaN(id)) {
      return res.status(400).json({ success: false, error: 'Ungültige Policy-ID' });
    }
    const { retentionDays, description, legalBasis, isActive } = req.body;

    const policy = await auditService.updateRetentionPolicy(id, {
      retentionDays,
      description,
      legalBasis,
      isActive,
    });

    await logChange({
      req, action: 'UPDATE', resourceType: 'RetentionPolicy',
      resourceId: id.toString(),
      label: `Aufbewahrungsrichtlinie aktualisiert`,
    });

    res.json({ success: true, data: policy });
  } catch (error) {
    console.error('Fehler beim Aktualisieren der Retention-Policy:', error);
    res.status(500).json({ success: false, error: 'Fehler beim Aktualisieren' });
  }
}

/**
 * Retention-Cleanup manuell ausführen
 */
export async function runRetentionCleanup(req: AuthRequest, res: Response) {
  try {
    const result = await auditService.runRetentionCleanup();

    res.json({
      success: true,
      data: result,
      message: `${result.deletedCount} alte Audit-Logs wurden gelöscht`,
    });
  } catch (error) {
    console.error('Fehler beim Retention-Cleanup:', error);
    res.status(500).json({ success: false, error: 'Fehler beim Cleanup' });
  }
}
