import { Request, Response } from 'express';
import * as invoiceService from '../services/invoice.service.js';
import { logChange } from '../services/audit.service.js';
import { ApiResponse, AuthRequest } from '../types/index.js';
import { canAccessContract, canAccessEnergyContractDetails } from '../utils/accessControl.js';

/**
 * Alle Rechnungen für ein EnergyContractDetails abrufen
 */
export async function getInvoices(req: AuthRequest, res: Response): Promise<void> {
  try {
    const ecdId = parseInt(req.params.ecdId);
    if (!(await canAccessEnergyContractDetails(req, res, ecdId))) return;
    const invoices = await invoiceService.getInvoices(ecdId);
    res.json({ success: true, data: invoices } as ApiResponse);
  } catch (error) {
    console.error('getInvoices error:', error);
    res.status(500).json({
      success: false,
      error: 'Fehler beim Laden der Rechnungen',
    } as ApiResponse);
  }
}

/**
 * Einzelne Rechnung abrufen
 */
export async function getInvoice(req: AuthRequest, res: Response): Promise<void> {
  try {
    const ecdId = parseInt(req.params.ecdId);
    const invoiceId = parseInt(req.params.invoiceId);
    if (!(await canAccessEnergyContractDetails(req, res, ecdId))) return;
    const invoice = await invoiceService.getInvoice(ecdId, invoiceId);

    if (!invoice) {
      res.status(404).json({
        success: false,
        error: 'Rechnung nicht gefunden',
      } as ApiResponse);
      return;
    }

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

/**
 * Neue Rechnung hinzufügen
 */
// Pentest 56.4 (MEDIUM, 2026-06-01): invoiceType wurde an manchen
// Endpunkten nicht gegen die Enum-Whitelist validiert; ein beliebiger
// String landete als invoiceType in der DB und konnte Frontend-
// Filter/Reports verwirren oder XSS in Audit-Labels einschleusen.
type ValidInvoiceType = 'INTERIM' | 'FINAL' | 'NOT_AVAILABLE';
const VALID_INVOICE_TYPES: Set<ValidInvoiceType> = new Set(['INTERIM', 'FINAL', 'NOT_AVAILABLE']);
function assertValidInvoiceType(value: unknown, res: Response): value is ValidInvoiceType {
  if (typeof value !== 'string' || !VALID_INVOICE_TYPES.has(value as ValidInvoiceType)) {
    res.status(400).json({
      success: false,
      error: `Ungültiger Rechnungstyp. Erlaubt: ${[...VALID_INVOICE_TYPES].join(', ')}.`,
    } as ApiResponse);
    return false;
  }
  return true;
}

export async function addInvoice(req: AuthRequest, res: Response): Promise<void> {
  try {
    const ecdId = parseInt(req.params.ecdId);
    if (!(await canAccessEnergyContractDetails(req, res, ecdId))) return;
    const { invoiceDate, invoiceType, documentPath, notes } = req.body;

    if (!invoiceDate || !invoiceType) {
      res.status(400).json({
        success: false,
        error: 'invoiceDate und invoiceType sind erforderlich',
      } as ApiResponse);
      return;
    }
    if (!assertValidInvoiceType(invoiceType, res)) return;

    const invoice = await invoiceService.addInvoice(ecdId, {
      invoiceDate: new Date(invoiceDate),
      invoiceType,
      documentPath,
      notes,
    });

    await logChange({
      req, action: 'CREATE', resourceType: 'Invoice',
      resourceId: invoice.id.toString(),
      label: `Rechnung (${invoiceType}) hinzugefügt`,
    });

    res.status(201).json({ success: true, data: invoice } as ApiResponse);
  } catch (error) {
    console.error('addInvoice error:', error);
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Hinzufügen der Rechnung',
    } as ApiResponse);
  }
}

/**
 * Rechnung aktualisieren
 */
export async function updateInvoice(req: AuthRequest, res: Response): Promise<void> {
  try {
    const ecdId = parseInt(req.params.ecdId);
    const invoiceId = parseInt(req.params.invoiceId);
    if (!(await canAccessEnergyContractDetails(req, res, ecdId))) return;
    const { invoiceDate, invoiceType, documentPath, notes } = req.body;
    // 56.4: invoiceType ist beim Update optional – nur prüfen wenn gesetzt.
    if (invoiceType !== undefined && !assertValidInvoiceType(invoiceType, res)) return;

    const invoice = await invoiceService.updateInvoice(ecdId, invoiceId, {
      invoiceDate: invoiceDate ? new Date(invoiceDate) : undefined,
      invoiceType,
      documentPath,
      notes,
    });

    await logChange({
      req, action: 'UPDATE', resourceType: 'Invoice',
      resourceId: invoiceId.toString(),
      label: `Rechnung aktualisiert`,
    });

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

/**
 * Rechnung löschen
 */
export async function deleteInvoice(req: AuthRequest, res: Response): Promise<void> {
  try {
    const ecdId = parseInt(req.params.ecdId);
    const invoiceId = parseInt(req.params.invoiceId);
    if (!(await canAccessEnergyContractDetails(req, res, ecdId))) return;

    await invoiceService.deleteInvoice(ecdId, invoiceId);

    await logChange({
      req, action: 'DELETE', resourceType: 'Invoice',
      resourceId: invoiceId.toString(),
      label: `Rechnung gelöscht`,
    });

    res.json({ success: true, data: null } as ApiResponse);
  } catch (error) {
    console.error('deleteInvoice error:', error);
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Löschen der Rechnung',
    } as ApiResponse);
  }
}

// ==================== CONTRACT-BASIERTE RECHNUNGEN (für alle Vertragstypen) ====================

export async function getInvoicesByContract(req: AuthRequest, res: Response): Promise<void> {
  try {
    const contractId = parseInt(req.params.id);
    if (!(await canAccessContract(req, res, contractId))) return;
    const invoices = await invoiceService.getInvoicesByContract(contractId);
    res.json({ success: true, data: invoices } as ApiResponse);
  } catch (error) {
    res.status(500).json({ success: false, error: 'Fehler beim Laden der Rechnungen' } as ApiResponse);
  }
}

export async function addInvoiceByContract(req: AuthRequest, res: Response): Promise<void> {
  try {
    const contractId = parseInt(req.params.id);
    if (!(await canAccessContract(req, res, contractId))) return;
    const { invoiceDate, invoiceType, notes } = req.body;
    if (!invoiceDate || !invoiceType) {
      res.status(400).json({
        success: false,
        error: 'invoiceDate und invoiceType sind erforderlich',
      } as ApiResponse);
      return;
    }
    if (!assertValidInvoiceType(invoiceType, res)) return;
    const invoice = await invoiceService.addInvoiceByContract(contractId, {
      invoiceDate: new Date(invoiceDate),
      invoiceType,
      notes,
    });
    await logChange({
      req, action: 'CREATE', resourceType: 'Invoice',
      resourceId: invoice.id.toString(),
      label: `Rechnung (${invoiceType}) hinzugefügt`,
    });
    res.status(201).json({ success: true, data: invoice } as ApiResponse);
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error instanceof Error ? error.message : 'Fehler beim Hinzufügen',
    } as ApiResponse);
  }
}
