import { Router, Response } from 'express';
import multer from 'multer';
import path from 'path';
import fs from 'fs';
import prisma from '../lib/prisma.js';
import { authenticate, requirePermission } from '../middleware/auth.js';
import { AuthRequest } from '../types/index.js';
import { logChange } from '../services/audit.service.js';
import {
  canAccessContract,
  canAccessCustomer,
  canAccessBankCard,
  canAccessIdentityDocument,
} from '../utils/accessControl.js';
import { validateOptionalIsoDate } from '../utils/sanitize.js';
import { validateUploadedFile } from '../middleware/uploadFileTypeValidator.js';
import { maybeCancelOnCancellationConfirmation, maybeMarkAwaitingConfirmationOnLetter } from '../services/contractStatusScheduler.service.js';
import { deleteFileAbsolute, deleteUploadByRelativePath } from '../utils/fileCleanup.js';

// Pentest 56.1 (HIGH, 2026-06-01): Upload-Endpoints prüften nur die
// Permission, nicht ob die Ziel-Resource zum Caller passt. Helper-Funktion
// für saubere 404-Antwort + Datei-Cleanup, wenn die Resource nicht
// existiert. Anschließend laufen die `canAccess*`-Checks (Portal-User
// werden dort auf ihre eigenen Kunden eingeschränkt; Staff bekommen
// volle Sicht – konsistent mit der bestehenden Access-Control-Logik).
async function resolveInvoiceContractId(invoiceId: number): Promise<number | null> {
  const invoice = await prisma.invoice.findUnique({
    where: { id: invoiceId },
    select: { contractId: true, energyContractDetails: { select: { contractId: true } } },
  });
  return invoice?.contractId ?? invoice?.energyContractDetails?.contractId ?? null;
}

const router = Router();

// Uploads-Verzeichnis erstellen falls nicht vorhanden
const uploadsDir = path.join(process.cwd(), 'uploads');
if (!fs.existsSync(uploadsDir)) {
  fs.mkdirSync(uploadsDir, { recursive: true });
}

// Multer-Konfiguration
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const subDir = (req as any).uploadSubDir || 'misc';
    const targetDir = path.join(uploadsDir, subDir);
    if (!fs.existsSync(targetDir)) {
      fs.mkdirSync(targetDir, { recursive: true });
    }
    cb(null, targetDir);
  },
  filename: (req, file, cb) => {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
    const ext = path.extname(file.originalname);
    cb(null, `${uniqueSuffix}${ext}`);
  },
});

const fileFilter = (
  req: Express.Request,
  file: Express.Multer.File,
  cb: multer.FileFilterCallback
) => {
  // PDFs + gängige Web-Bildformate. WebP + GIF nachgezogen 2026-05-30
  // (Pentest INFO: WebP/GIF lieferten 500 statt sauberem 4xx, weil
  // erlaubter MIME-Type fehlte und der fileFilter dann throwte).
  const allowedTypes = [
    'application/pdf',
    'image/jpeg', 'image/jpg', 'image/png',
    'image/gif', 'image/webp',
  ];
  if (allowedTypes.includes(file.mimetype)) {
    cb(null, true);
  } else {
    cb(new Error('Nur PDF, JPG, PNG, GIF und WebP-Dateien sind erlaubt'));
  }
};

const upload = multer({
  storage,
  fileFilter,
  limits: {
    // 25 MB – passt für Ausweis-Scans, Handy-Photos im JpgToPdf-Flow,
    // mehrseitige PDFs aus dem Modal (bis ~5-7 Seiten je nach Auflösung).
    // Vorher 10 MB → Multer brach bei zwei Smartphone-Fotos ab.
    fileSize: 25 * 1024 * 1024,
  },
});

// Middleware um Subdirectory zu setzen
function setUploadDir(subDir: string) {
  return (req: AuthRequest, res: Response, next: Function) => {
    (req as any).uploadSubDir = subDir;
    next();
  };
}

// Magic-Byte-Whitelist + canonical Rename + PDF-Scan: siehe
// middleware/uploadFileTypeValidator.ts (zentralisiert, damit auch
// contract.routes.ts denselben Check fahren kann – Pentest 69.3).

// Upload für Bankkarten-Dokumente
router.post(
  '/bank-cards/:id',
  authenticate,
  requirePermission('customers:update'),
  setUploadDir('bank-cards'),
  upload.single('document'),
  validateUploadedFile,
  async (req: AuthRequest, res: Response) => {
    try {
      if (!req.file) {
        res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
        return;
      }

      const bankCardId = parseInt(req.params.id);
      // Pentest 56.1: Existenz- und Ownership-Check VOR DB-Update.
      const card = await prisma.bankCard.findUnique({ where: { id: bankCardId } });
      if (!card) {
        deleteFileAbsolute(req.file.path);
        res.status(404).json({ success: false, error: 'Bankkarte nicht gefunden' });
        return;
      }
      if (!(await canAccessBankCard(req, res, bankCardId))) {
        deleteFileAbsolute(req.file.path);
        return;
      }

      const relativePath = `/uploads/bank-cards/${req.file.filename}`;

      await prisma.bankCard.update({
        where: { id: bankCardId },
        data: { documentPath: relativePath },
      });

      res.json({
        success: true,
        data: {
          path: relativePath,
          filename: req.file.filename,
          originalName: req.file.originalname,
          size: req.file.size,
        },
      });
    } catch (error) {
      console.error('Upload error:', error);
      deleteFileAbsolute(req.file?.path);
      res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
    }
  }
);

// Upload für Ausweis-Dokumente
router.post(
  '/documents/:id',
  authenticate,
  requirePermission('customers:update'),
  setUploadDir('documents'),
  upload.single('document'),
  validateUploadedFile,
  async (req: AuthRequest, res: Response) => {
    try {
      if (!req.file) {
        res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
        return;
      }

      const documentId = parseInt(req.params.id);
      // Pentest 56.1: Existenz- und Ownership-Check VOR DB-Update.
      const doc = await prisma.identityDocument.findUnique({ where: { id: documentId } });
      if (!doc) {
        deleteFileAbsolute(req.file.path);
        res.status(404).json({ success: false, error: 'Ausweis nicht gefunden' });
        return;
      }
      if (!(await canAccessIdentityDocument(req, res, documentId))) {
        deleteFileAbsolute(req.file.path);
        return;
      }

      const relativePath = `/uploads/documents/${req.file.filename}`;

      await prisma.identityDocument.update({
        where: { id: documentId },
        data: { documentPath: relativePath },
      });

      res.json({
        success: true,
        data: {
          path: relativePath,
          filename: req.file.filename,
          originalName: req.file.originalname,
          size: req.file.size,
        },
      });
    } catch (error) {
      console.error('Upload error:', error);
      deleteFileAbsolute(req.file?.path);
      res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
    }
  }
);

// Löschen von Bankkarten-Dokumenten
router.delete(
  '/bank-cards/:id',
  authenticate,
  requirePermission('customers:update'),
  async (req: AuthRequest, res: Response) => {
    try {
      const bankCardId = parseInt(req.params.id);

      // Bankkarte aus DB holen um Dateipfad zu bekommen
      const bankCard = await prisma.bankCard.findUnique({
        where: { id: bankCardId },
      });

      if (!bankCard) {
        res.status(404).json({ success: false, error: 'Bankkarte nicht gefunden' });
        return;
      }
      // Pentest 56.1: Ownership-Check.
      if (!(await canAccessBankCard(req, res, bankCardId))) return;

      if (!bankCard.documentPath) {
        res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
        return;
      }

      // Datei von Festplatte löschen
      const filePath = path.join(process.cwd(), bankCard.documentPath);
      if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
      }

      // documentPath in DB auf null setzen
      await prisma.bankCard.update({
        where: { id: bankCardId },
        data: { documentPath: null },
      });

      res.json({ success: true });
    } catch (error) {
      console.error('Delete error:', error);
      res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
    }
  }
);

// Löschen von Ausweis-Dokumenten
router.delete(
  '/documents/:id',
  authenticate,
  requirePermission('customers:update'),
  async (req: AuthRequest, res: Response) => {
    try {
      const documentId = parseInt(req.params.id);

      // Ausweis aus DB holen um Dateipfad zu bekommen
      const document = await prisma.identityDocument.findUnique({
        where: { id: documentId },
      });

      if (!document) {
        res.status(404).json({ success: false, error: 'Ausweis nicht gefunden' });
        return;
      }
      // Pentest 56.1: Ownership-Check.
      if (!(await canAccessIdentityDocument(req, res, documentId))) return;

      if (!document.documentPath) {
        res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
        return;
      }

      // Datei von Festplatte löschen
      const filePath = path.join(process.cwd(), document.documentPath);
      if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
      }

      // documentPath in DB auf null setzen
      await prisma.identityDocument.update({
        where: { id: documentId },
        data: { documentPath: null },
      });

      res.json({ success: true });
    } catch (error) {
      console.error('Delete error:', error);
      res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
    }
  }
);

// ==================== FIRMEN-DOKUMENTE ====================

// Upload für Gewerbeanmeldung
router.post(
  '/customers/:id/business-registration',
  authenticate,
  requirePermission('customers:update'),
  setUploadDir('business-registrations'),
  upload.single('document'),
  validateUploadedFile,
  async (req: AuthRequest, res: Response) => {
    try {
      if (!req.file) {
        res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
        return;
      }

      const customerId = parseInt(req.params.id);
      // Pentest 56.1: Ownership-Check.
      if (!(await canAccessCustomer(req, res, customerId))) {
        deleteFileAbsolute(req.file.path);
        return;
      }
      const relativePath = `/uploads/business-registrations/${req.file.filename}`;

      // Alte Datei löschen falls vorhanden
      const customer = await prisma.customer.findUnique({ where: { id: customerId } });
      if (customer?.businessRegistrationPath) {
        const oldPath = path.join(process.cwd(), customer.businessRegistrationPath);
        if (fs.existsSync(oldPath)) {
          fs.unlinkSync(oldPath);
        }
      }

      // Kunde in der DB aktualisieren
      await prisma.customer.update({
        where: { id: customerId },
        data: { businessRegistrationPath: relativePath },
      });

      res.json({
        success: true,
        data: {
          path: relativePath,
          filename: req.file.filename,
          originalName: req.file.originalname,
          size: req.file.size,
        },
      });
    } catch (error) {
      console.error('Upload error:', error);
      res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
    }
  }
);

// Upload für Handelsregisterauszug
router.post(
  '/customers/:id/commercial-register',
  authenticate,
  requirePermission('customers:update'),
  setUploadDir('commercial-registers'),
  upload.single('document'),
  validateUploadedFile,
  async (req: AuthRequest, res: Response) => {
    try {
      if (!req.file) {
        res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
        return;
      }

      const customerId = parseInt(req.params.id);
      // Pentest 56.1: Ownership-Check.
      if (!(await canAccessCustomer(req, res, customerId))) {
        deleteFileAbsolute(req.file.path);
        return;
      }
      const relativePath = `/uploads/commercial-registers/${req.file.filename}`;

      // Alte Datei löschen falls vorhanden
      const customer = await prisma.customer.findUnique({ where: { id: customerId } });
      if (customer?.commercialRegisterPath) {
        const oldPath = path.join(process.cwd(), customer.commercialRegisterPath);
        if (fs.existsSync(oldPath)) {
          fs.unlinkSync(oldPath);
        }
      }

      // Kunde in der DB aktualisieren
      await prisma.customer.update({
        where: { id: customerId },
        data: { commercialRegisterPath: relativePath },
      });

      res.json({
        success: true,
        data: {
          path: relativePath,
          filename: req.file.filename,
          originalName: req.file.originalname,
          size: req.file.size,
        },
      });
    } catch (error) {
      console.error('Upload error:', error);
      res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
    }
  }
);

// Löschen der Gewerbeanmeldung
router.delete(
  '/customers/:id/business-registration',
  authenticate,
  requirePermission('customers:update'),
  async (req: AuthRequest, res: Response) => {
    try {
      const customerId = parseInt(req.params.id);
      // Pentest 56.1: Ownership-Check.
      if (!(await canAccessCustomer(req, res, customerId))) return;

      const customer = await prisma.customer.findUnique({ where: { id: customerId } });
      if (!customer) {
        res.status(404).json({ success: false, error: 'Kunde nicht gefunden' });
        return;
      }

      if (!customer.businessRegistrationPath) {
        res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
        return;
      }

      // Datei löschen
      const filePath = path.join(process.cwd(), customer.businessRegistrationPath);
      if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
      }

      // Pfad in DB auf null setzen
      await prisma.customer.update({
        where: { id: customerId },
        data: { businessRegistrationPath: null },
      });

      res.json({ success: true });
    } catch (error) {
      console.error('Delete error:', error);
      res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
    }
  }
);

// Löschen des Handelsregisterauszugs
router.delete(
  '/customers/:id/commercial-register',
  authenticate,
  requirePermission('customers:update'),
  async (req: AuthRequest, res: Response) => {
    try {
      const customerId = parseInt(req.params.id);
      // Pentest 56.1: Ownership-Check.
      if (!(await canAccessCustomer(req, res, customerId))) return;

      const customer = await prisma.customer.findUnique({ where: { id: customerId } });
      if (!customer) {
        res.status(404).json({ success: false, error: 'Kunde nicht gefunden' });
        return;
      }

      if (!customer.commercialRegisterPath) {
        res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
        return;
      }

      // Datei löschen
      const filePath = path.join(process.cwd(), customer.commercialRegisterPath);
      if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
      }

      // Pfad in DB auf null setzen
      await prisma.customer.update({
        where: { id: customerId },
        data: { commercialRegisterPath: null },
      });

      res.json({ success: true });
    } catch (error) {
      console.error('Delete error:', error);
      res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
    }
  }
);

// ==================== DATENSCHUTZERKLÄRUNG (für alle Kunden) ====================

// Upload für Datenschutzerklärung
router.post(
  '/customers/:id/privacy-policy',
  authenticate,
  requirePermission('customers:update'),
  setUploadDir('privacy-policies'),
  upload.single('document'),
  validateUploadedFile,
  async (req: AuthRequest, res: Response) => {
    try {
      if (!req.file) {
        res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
        return;
      }

      const customerId = parseInt(req.params.id);
      // Pentest 56.2 (HIGH): Ownership-Check VOR Consent-Massen-Update.
      // Ohne diese Prüfung konnte jeder Caller mit customers:update für
      // jede beliebige customerId ALLE Einwilligungen auf GRANTED setzen
      // (DSGVO-Eskalation).
      if (!(await canAccessCustomer(req, res, customerId))) {
        deleteFileAbsolute(req.file.path);
        return;
      }
      const relativePath = `/uploads/privacy-policies/${req.file.filename}`;

      // Alte Datei löschen falls vorhanden
      const customer = await prisma.customer.findUnique({ where: { id: customerId } });
      if (customer?.privacyPolicyPath) {
        const oldPath = path.join(process.cwd(), customer.privacyPolicyPath);
        if (fs.existsSync(oldPath)) {
          fs.unlinkSync(oldPath);
        }
      }

      // Kunde in der DB aktualisieren
      await prisma.customer.update({
        where: { id: customerId },
        data: { privacyPolicyPath: relativePath },
      });

      // Alle Consents auf GRANTED setzen (PDF = vollständige Einwilligung)
      const consentTypes = ['DATA_PROCESSING', 'MARKETING_EMAIL', 'MARKETING_PHONE', 'DATA_SHARING_PARTNER'] as const;
      for (const consentType of consentTypes) {
        await prisma.customerConsent.upsert({
          where: { customerId_consentType: { customerId, consentType } },
          update: { status: 'GRANTED', grantedAt: new Date(), source: 'papier' },
          create: { customerId, consentType, status: 'GRANTED', grantedAt: new Date(), source: 'papier', createdBy: (req as any).user?.email || 'admin' },
        });
      }

      // Audit
      const cust = await prisma.customer.findUnique({ where: { id: customerId }, select: { firstName: true, lastName: true } });
      await logChange({
        req, action: 'CREATE', resourceType: 'CustomerConsent',
        label: `Datenschutzerklärung-PDF hochgeladen für ${cust?.firstName} ${cust?.lastName} – alle Einwilligungen erteilt`,
        details: { aktion: 'PDF hochgeladen', einwilligungen: 'alle erteilt', quelle: 'papier' },
        customerId,
      });

      res.json({
        success: true,
        data: {
          path: relativePath,
          filename: req.file.filename,
          originalName: req.file.originalname,
          size: req.file.size,
        },
      });
    } catch (error) {
      console.error('Upload error:', error);
      res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
    }
  }
);

// Löschen der Datenschutzerklärung
router.delete(
  '/customers/:id/privacy-policy',
  authenticate,
  requirePermission('customers:update'),
  async (req: AuthRequest, res: Response) => {
    try {
      const customerId = parseInt(req.params.id);
      // Pentest 56.1: Ownership-Check.
      if (!(await canAccessCustomer(req, res, customerId))) return;

      const customer = await prisma.customer.findUnique({ where: { id: customerId } });
      if (!customer) {
        res.status(404).json({ success: false, error: 'Kunde nicht gefunden' });
        return;
      }

      if (!customer.privacyPolicyPath) {
        res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
        return;
      }

      // Datei löschen
      const filePath = path.join(process.cwd(), customer.privacyPolicyPath);
      if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
      }

      // Pfad in DB auf null setzen
      await prisma.customer.update({
        where: { id: customerId },
        data: { privacyPolicyPath: null },
      });

      // Nur Consents widerrufen die per Papier erteilt wurden
      await prisma.customerConsent.updateMany({
        where: { customerId, status: 'GRANTED', source: 'papier' },
        data: { status: 'WITHDRAWN', withdrawnAt: new Date() },
      });

      // Audit
      const cust = await prisma.customer.findUnique({ where: { id: customerId }, select: { firstName: true, lastName: true } });
      await logChange({
        req, action: 'DELETE', resourceType: 'CustomerConsent',
        label: `Datenschutzerklärung-PDF gelöscht für ${cust?.firstName} ${cust?.lastName} – Papier-Einwilligungen widerrufen`,
        details: { aktion: 'PDF gelöscht', einwilligungen: 'papier-basierte widerrufen' },
        customerId,
      });

      res.json({ success: true });
    } catch (error) {
      console.error('Delete error:', error);
      res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
    }
  }
);

// ==================== VERTRAGS-DOKUMENTE ====================

// Generische Funktion für Vertrags-Dokument Upload
async function handleContractDocumentUpload(
  req: AuthRequest,
  res: Response,
  fieldName: 'cancellationLetterPath' | 'cancellationConfirmationPath' | 'cancellationLetterOptionsPath' | 'cancellationConfirmationOptionsPath',
  subDir: string
) {
  try {
    if (!req.file) {
      res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
      return;
    }

    const contractId = parseInt(req.params.id);
    if (!(await canAccessContract(req, res, contractId))) return;
    const relativePath = `/uploads/${subDir}/${req.file.filename}`;

    // Alte Datei löschen falls vorhanden
    const contract = await prisma.contract.findUnique({ where: { id: contractId } });
    if (!contract) {
      res.status(404).json({ success: false, error: 'Vertrag nicht gefunden' });
      return;
    }

    const oldPath = contract[fieldName];
    if (oldPath) {
      const fullPath = path.join(process.cwd(), oldPath);
      if (fs.existsSync(fullPath)) {
        fs.unlinkSync(fullPath);
      }
    }

    // Bei Kündigungsbestätigung(s-Optionen): optionales Datum aus multipart
    // übernehmen. Ohne Angabe: falls Feld noch leer → heute, sonst nicht anfassen.
    const updateData: Record<string, unknown> = { [fieldName]: relativePath };
    if (fieldName === 'cancellationConfirmationPath' || fieldName === 'cancellationConfirmationOptionsPath') {
      const dateField = fieldName === 'cancellationConfirmationPath'
        ? 'cancellationConfirmationDate'
        : 'cancellationConfirmationOptionsDate';
      // Pentest 62.7: confirmationDate gegen ISO-8601 validieren.
      let provided: string | null;
      try {
        provided = validateOptionalIsoDate(req.body?.confirmationDate, 'confirmationDate');
      } catch (err) {
        deleteFileAbsolute(req.file?.path);
        res.status(400).json({ success: false, error: err instanceof Error ? err.message : 'Ungültiges Bestätigungsdatum' });
        return;
      }
      let target: Date | null = null;
      if (provided) {
        target = new Date(provided);
      }
      if (target) {
        updateData[dateField] = target;
      } else if (!contract[dateField]) {
        updateData[dateField] = new Date();
      }
    }

    // Vertrag in der DB aktualisieren
    await prisma.contract.update({
      where: { id: contractId },
      data: updateData,
    });

    // Kündigungsbestätigung (nicht "Optionen") hochgeladen → Vertrag auf
    // "Gekündigt / bestätigt" (CANCELLED_CONFIRMED) + Vertragsende = Kündigungs-
    // datum. "Optionen" ist für Vertrags-Änderungen gedacht, nicht für Kündigungen.
    if (fieldName === 'cancellationConfirmationPath') {
      await maybeCancelOnCancellationConfirmation(contractId, req);
    }
    // Kündigungsschreiben hochgeladen → Vertrag auf "Gekündigt / Bestätigung
    // abwarten" (CANCELLED), sofern noch nicht (bestätigt) gekündigt.
    if (fieldName === 'cancellationLetterPath') {
      await maybeMarkAwaitingConfirmationOnLetter(contractId, req);
    }

    res.json({
      success: true,
      data: {
        path: relativePath,
        filename: req.file.filename,
        originalName: req.file.originalname,
        size: req.file.size,
      },
    });
  } catch (error) {
    console.error('Upload error:', error);
    res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
  }
}

// Generische Funktion für Vertrags-Dokument Löschen
async function handleContractDocumentDelete(
  req: AuthRequest,
  res: Response,
  fieldName: 'cancellationLetterPath' | 'cancellationConfirmationPath' | 'cancellationLetterOptionsPath' | 'cancellationConfirmationOptionsPath'
) {
  try {
    const contractId = parseInt(req.params.id);
    if (!(await canAccessContract(req, res, contractId))) return;

    const contract = await prisma.contract.findUnique({ where: { id: contractId } });
    if (!contract) {
      res.status(404).json({ success: false, error: 'Vertrag nicht gefunden' });
      return;
    }

    const documentPath = contract[fieldName];
    if (!documentPath) {
      res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
      return;
    }

    // Datei löschen
    const filePath = path.join(process.cwd(), documentPath);
    if (fs.existsSync(filePath)) {
      fs.unlinkSync(filePath);
    }

    // Pfad in DB auf null setzen
    await prisma.contract.update({
      where: { id: contractId },
      data: { [fieldName]: null },
    });

    res.json({ success: true });
  } catch (error) {
    console.error('Delete error:', error);
    res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
  }
}

// Kündigungsschreiben
router.post(
  '/contracts/:id/cancellation-letter',
  authenticate,
  requirePermission('contracts:update'),
  setUploadDir('cancellation-letters'),
  upload.single('document'),
  validateUploadedFile,
  (req: AuthRequest, res: Response) => handleContractDocumentUpload(req, res, 'cancellationLetterPath', 'cancellation-letters')
);

router.delete(
  '/contracts/:id/cancellation-letter',
  authenticate,
  requirePermission('contracts:update'),
  (req: AuthRequest, res: Response) => handleContractDocumentDelete(req, res, 'cancellationLetterPath')
);

// Kündigungsbestätigung
router.post(
  '/contracts/:id/cancellation-confirmation',
  authenticate,
  requirePermission('contracts:update'),
  setUploadDir('cancellation-confirmations'),
  upload.single('document'),
  validateUploadedFile,
  (req: AuthRequest, res: Response) => handleContractDocumentUpload(req, res, 'cancellationConfirmationPath', 'cancellation-confirmations')
);

router.delete(
  '/contracts/:id/cancellation-confirmation',
  authenticate,
  requirePermission('contracts:update'),
  (req: AuthRequest, res: Response) => handleContractDocumentDelete(req, res, 'cancellationConfirmationPath')
);

// Kündigungsschreiben Optionen
router.post(
  '/contracts/:id/cancellation-letter-options',
  authenticate,
  requirePermission('contracts:update'),
  setUploadDir('cancellation-letters-options'),
  upload.single('document'),
  validateUploadedFile,
  (req: AuthRequest, res: Response) => handleContractDocumentUpload(req, res, 'cancellationLetterOptionsPath', 'cancellation-letters-options')
);

router.delete(
  '/contracts/:id/cancellation-letter-options',
  authenticate,
  requirePermission('contracts:update'),
  (req: AuthRequest, res: Response) => handleContractDocumentDelete(req, res, 'cancellationLetterOptionsPath')
);

// Kündigungsbestätigung Optionen
router.post(
  '/contracts/:id/cancellation-confirmation-options',
  authenticate,
  requirePermission('contracts:update'),
  setUploadDir('cancellation-confirmations-options'),
  upload.single('document'),
  validateUploadedFile,
  (req: AuthRequest, res: Response) => handleContractDocumentUpload(req, res, 'cancellationConfirmationOptionsPath', 'cancellation-confirmations-options')
);

router.delete(
  '/contracts/:id/cancellation-confirmation-options',
  authenticate,
  requirePermission('contracts:update'),
  (req: AuthRequest, res: Response) => handleContractDocumentDelete(req, res, 'cancellationConfirmationOptionsPath')
);

// ==================== RECHNUNGS-DOKUMENTE ====================

// Upload für Rechnungs-Dokument
router.post(
  '/invoices/:id',
  authenticate,
  requirePermission('contracts:update'),
  setUploadDir('invoices'),
  upload.single('document'),
  validateUploadedFile,
  async (req: AuthRequest, res: Response) => {
    try {
      if (!req.file) {
        res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
        return;
      }

      const invoiceId = parseInt(req.params.id);
      // Pentest 56.1: Existenz- und Ownership-Check VOR DB-Update.
      const invoice = await prisma.invoice.findUnique({ where: { id: invoiceId } });
      if (!invoice) {
        deleteFileAbsolute(req.file.path);
        res.status(404).json({ success: false, error: 'Rechnung nicht gefunden' });
        return;
      }
      const invoiceContractId = await resolveInvoiceContractId(invoiceId);
      if (invoiceContractId == null || !(await canAccessContract(req, res, invoiceContractId))) {
        deleteFileAbsolute(req.file.path);
        return;
      }

      const relativePath = `/uploads/invoices/${req.file.filename}`;

      if (invoice.documentPath) {
        const oldPath = path.join(process.cwd(), invoice.documentPath);
        if (fs.existsSync(oldPath)) {
          fs.unlinkSync(oldPath);
        }
      }

      // Invoice in der DB aktualisieren
      await prisma.invoice.update({
        where: { id: invoiceId },
        data: { documentPath: relativePath },
      });

      res.json({
        success: true,
        data: {
          path: relativePath,
          filename: req.file.filename,
          originalName: req.file.originalname,
          size: req.file.size,
        },
      });
    } catch (error) {
      console.error('Invoice upload error:', error);
      res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
    }
  }
);

// Löschen von Rechnungs-Dokument
router.delete(
  '/invoices/:id',
  authenticate,
  requirePermission('contracts:update'),
  async (req: AuthRequest, res: Response) => {
    try {
      const invoiceId = parseInt(req.params.id);

      const invoice = await prisma.invoice.findUnique({ where: { id: invoiceId } });
      if (!invoice) {
        res.status(404).json({ success: false, error: 'Rechnung nicht gefunden' });
        return;
      }
      // Pentest 56.1: Ownership-Check vor Delete.
      const invoiceContractId = await resolveInvoiceContractId(invoiceId);
      if (invoiceContractId == null || !(await canAccessContract(req, res, invoiceContractId))) return;

      if (!invoice.documentPath) {
        res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
        return;
      }

      // Datei löschen
      const filePath = path.join(process.cwd(), invoice.documentPath);
      if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
      }

      // documentPath in DB auf null setzen
      await prisma.invoice.update({
        where: { id: invoiceId },
        data: { documentPath: null },
      });

      res.json({ success: true });
    } catch (error) {
      console.error('Invoice delete error:', error);
      res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
    }
  }
);

// Upload für Gutschrift-Überweisungsbeleg. Interner Bereich → Portal blocken.
router.post(
  '/credit-notes/:id/receipt',
  authenticate,
  requirePermission('contracts:update'),
  setUploadDir('credit-note-receipts'),
  upload.single('document'),
  validateUploadedFile,
  async (req: AuthRequest, res: Response) => {
    try {
      if (req.user?.isCustomerPortal) {
        deleteFileAbsolute(req.file?.path);
        res.status(403).json({ success: false, error: 'Kein Zugriff' });
        return;
      }
      if (!req.file) {
        res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
        return;
      }
      const id = parseInt(req.params.id);
      const cn = await prisma.creditNote.findUnique({
        where: { id },
        select: { contractId: true, receiptPath: true },
      });
      if (!cn) {
        deleteFileAbsolute(req.file.path);
        res.status(404).json({ success: false, error: 'Gutschrift nicht gefunden' });
        return;
      }
      if (!(await canAccessContract(req, res, cn.contractId))) {
        deleteFileAbsolute(req.file.path);
        return;
      }
      const relativePath = `/uploads/credit-note-receipts/${req.file.filename}`;
      deleteUploadByRelativePath(cn.receiptPath);
      await prisma.creditNote.update({ where: { id }, data: { receiptPath: relativePath } });
      await logChange({
        req, action: 'UPDATE', resourceType: 'CreditNote', resourceId: id.toString(),
        label: 'Überweisungsbeleg zur Gutschrift hochgeladen',
      });
      res.json({ success: true, data: { receiptPath: relativePath } });
    } catch (error) {
      console.error('Credit-note receipt upload error:', error);
      deleteFileAbsolute(req.file?.path);
      res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
    }
  }
);

router.delete(
  '/credit-notes/:id/receipt',
  authenticate,
  requirePermission('contracts:update'),
  async (req: AuthRequest, res: Response) => {
    try {
      if (req.user?.isCustomerPortal) {
        res.status(403).json({ success: false, error: 'Kein Zugriff' });
        return;
      }
      const id = parseInt(req.params.id);
      const cn = await prisma.creditNote.findUnique({
        where: { id },
        select: { contractId: true, receiptPath: true },
      });
      if (!cn) {
        res.status(404).json({ success: false, error: 'Gutschrift nicht gefunden' });
        return;
      }
      if (!(await canAccessContract(req, res, cn.contractId))) return;
      deleteUploadByRelativePath(cn.receiptPath);
      await prisma.creditNote.update({ where: { id }, data: { receiptPath: null } });
      await logChange({
        req, action: 'UPDATE', resourceType: 'CreditNote', resourceId: id.toString(),
        label: 'Überweisungsbeleg zur Gutschrift entfernt',
      });
      res.json({ success: true });
    } catch (error) {
      console.error('Credit-note receipt delete error:', error);
      res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
    }
  }
);

export default router;
