import { Router, Response } from 'express';
import prisma from '../lib/prisma.js';
import { authenticate, requirePermission } from '../middleware/auth.js';
import { AuthRequest } from '../types/index.js';

const router = Router();

// HINWEIS: Der frühere `POST /setup`-Endpoint wurde entfernt (Pentest Runde 3
// 2026-05-16 – KRITISCH). Er war ohne Auth erreichbar und konnte
// `developer:access` an die Admin-Rolle hängen → Privilege-Escalation auf
// volle DB-Kontrolle. Wenn die developer:access-Permission manuell gesetzt
// werden muss, gibt es das CLI-Script `prisma/add-developer-permission.ts`.

// Tabellen-Metadaten mit Beziehungen
const tableMetadata: Record<string, {
  model: string;
  primaryKey: string;
  readonlyFields: string[];
  requiredFields: string[];
  relations: { field: string; targetTable: string; type: 'one' | 'many' }[];
  foreignKeys: { field: string; targetTable: string }[];
}> = {
  User: {
    model: 'user',
    primaryKey: 'id',
    readonlyFields: ['id', 'createdAt', 'updatedAt', 'password'],
    requiredFields: ['email', 'firstName', 'lastName'],
    relations: [
      { field: 'customer', targetTable: 'Customer', type: 'one' },
      { field: 'roles', targetTable: 'UserRole', type: 'many' },
    ],
    foreignKeys: [{ field: 'customerId', targetTable: 'Customer' }],
  },
  Role: {
    model: 'role',
    primaryKey: 'id',
    readonlyFields: ['id', 'createdAt', 'updatedAt'],
    requiredFields: ['name'],
    relations: [
      { field: 'permissions', targetTable: 'RolePermission', type: 'many' },
      { field: 'users', targetTable: 'UserRole', type: 'many' },
    ],
    foreignKeys: [],
  },
  Permission: {
    model: 'permission',
    primaryKey: 'id',
    readonlyFields: ['id'],
    requiredFields: ['resource', 'action'],
    relations: [{ field: 'roles', targetTable: 'RolePermission', type: 'many' }],
    foreignKeys: [],
  },
  RolePermission: {
    model: 'rolePermission',
    primaryKey: 'roleId,permissionId',
    readonlyFields: [],
    requiredFields: ['roleId', 'permissionId'],
    relations: [],
    foreignKeys: [
      { field: 'roleId', targetTable: 'Role' },
      { field: 'permissionId', targetTable: 'Permission' },
    ],
  },
  UserRole: {
    model: 'userRole',
    primaryKey: 'userId,roleId',
    readonlyFields: [],
    requiredFields: ['userId', 'roleId'],
    relations: [],
    foreignKeys: [
      { field: 'userId', targetTable: 'User' },
      { field: 'roleId', targetTable: 'Role' },
    ],
  },
  Customer: {
    model: 'customer',
    primaryKey: 'id',
    readonlyFields: ['id', 'createdAt', 'updatedAt', 'customerNumber'],
    requiredFields: ['firstName', 'lastName'],
    relations: [
      { field: 'user', targetTable: 'User', type: 'one' },
      { field: 'addresses', targetTable: 'Address', type: 'many' },
      { field: 'bankCards', targetTable: 'BankCard', type: 'many' },
      { field: 'identityDocuments', targetTable: 'IdentityDocument', type: 'many' },
      { field: 'meters', targetTable: 'Meter', type: 'many' },
      { field: 'contracts', targetTable: 'Contract', type: 'many' },
    ],
    foreignKeys: [],
  },
  Address: {
    model: 'address',
    primaryKey: 'id',
    readonlyFields: ['id', 'createdAt', 'updatedAt'],
    requiredFields: ['customerId', 'street', 'houseNumber', 'postalCode', 'city'],
    relations: [
      { field: 'customer', targetTable: 'Customer', type: 'one' },
      { field: 'contracts', targetTable: 'Contract', type: 'many' },
    ],
    foreignKeys: [{ field: 'customerId', targetTable: 'Customer' }],
  },
  BankCard: {
    model: 'bankCard',
    primaryKey: 'id',
    readonlyFields: ['id', 'createdAt', 'updatedAt'],
    requiredFields: ['customerId', 'accountHolder', 'iban'],
    relations: [
      { field: 'customer', targetTable: 'Customer', type: 'one' },
      { field: 'contracts', targetTable: 'Contract', type: 'many' },
    ],
    foreignKeys: [{ field: 'customerId', targetTable: 'Customer' }],
  },
  IdentityDocument: {
    model: 'identityDocument',
    primaryKey: 'id',
    readonlyFields: ['id', 'createdAt', 'updatedAt'],
    requiredFields: ['customerId', 'documentNumber'],
    relations: [
      { field: 'customer', targetTable: 'Customer', type: 'one' },
      { field: 'contracts', targetTable: 'Contract', type: 'many' },
    ],
    foreignKeys: [{ field: 'customerId', targetTable: 'Customer' }],
  },
  Meter: {
    model: 'meter',
    primaryKey: 'id',
    readonlyFields: ['id', 'createdAt', 'updatedAt'],
    requiredFields: ['customerId', 'meterNumber', 'type'],
    relations: [
      { field: 'customer', targetTable: 'Customer', type: 'one' },
      { field: 'readings', targetTable: 'MeterReading', type: 'many' },
      { field: 'energyDetails', targetTable: 'EnergyContractDetails', type: 'many' },
    ],
    foreignKeys: [{ field: 'customerId', targetTable: 'Customer' }],
  },
  MeterReading: {
    model: 'meterReading',
    primaryKey: 'id',
    readonlyFields: ['id', 'createdAt'],
    requiredFields: ['meterId', 'readingDate', 'value'],
    relations: [{ field: 'meter', targetTable: 'Meter', type: 'one' }],
    foreignKeys: [{ field: 'meterId', targetTable: 'Meter' }],
  },
  SalesPlatform: {
    model: 'salesPlatform',
    primaryKey: 'id',
    readonlyFields: ['id', 'createdAt', 'updatedAt'],
    requiredFields: ['name'],
    relations: [{ field: 'contracts', targetTable: 'Contract', type: 'many' }],
    foreignKeys: [],
  },
  Contract: {
    model: 'contract',
    primaryKey: 'id',
    readonlyFields: ['id', 'createdAt', 'updatedAt', 'contractNumber'],
    requiredFields: ['customerId', 'type'],
    relations: [
      { field: 'customer', targetTable: 'Customer', type: 'one' },
      { field: 'address', targetTable: 'Address', type: 'one' },
      { field: 'bankCard', targetTable: 'BankCard', type: 'one' },
      { field: 'identityDocument', targetTable: 'IdentityDocument', type: 'one' },
      { field: 'salesPlatform', targetTable: 'SalesPlatform', type: 'one' },
      { field: 'previousContract', targetTable: 'Contract', type: 'one' },
      { field: 'followUpContract', targetTable: 'Contract', type: 'one' },
      { field: 'energyDetails', targetTable: 'EnergyContractDetails', type: 'one' },
      { field: 'internetDetails', targetTable: 'InternetContractDetails', type: 'one' },
      { field: 'mobileDetails', targetTable: 'MobileContractDetails', type: 'one' },
      { field: 'tvDetails', targetTable: 'TvContractDetails', type: 'one' },
      { field: 'carInsuranceDetails', targetTable: 'CarInsuranceDetails', type: 'one' },
    ],
    foreignKeys: [
      { field: 'customerId', targetTable: 'Customer' },
      { field: 'addressId', targetTable: 'Address' },
      { field: 'bankCardId', targetTable: 'BankCard' },
      { field: 'identityDocumentId', targetTable: 'IdentityDocument' },
      { field: 'salesPlatformId', targetTable: 'SalesPlatform' },
      { field: 'previousContractId', targetTable: 'Contract' },
    ],
  },
  EnergyContractDetails: {
    model: 'energyContractDetails',
    primaryKey: 'id',
    readonlyFields: ['id'],
    requiredFields: ['contractId'],
    relations: [
      { field: 'contract', targetTable: 'Contract', type: 'one' },
      { field: 'meter', targetTable: 'Meter', type: 'one' },
    ],
    foreignKeys: [
      { field: 'contractId', targetTable: 'Contract' },
      { field: 'meterId', targetTable: 'Meter' },
    ],
  },
  InternetContractDetails: {
    model: 'internetContractDetails',
    primaryKey: 'id',
    readonlyFields: ['id'],
    requiredFields: ['contractId'],
    relations: [
      { field: 'contract', targetTable: 'Contract', type: 'one' },
      { field: 'phoneNumbers', targetTable: 'PhoneNumber', type: 'many' },
    ],
    foreignKeys: [{ field: 'contractId', targetTable: 'Contract' }],
  },
  PhoneNumber: {
    model: 'phoneNumber',
    primaryKey: 'id',
    readonlyFields: ['id'],
    requiredFields: ['internetContractDetailsId', 'phoneNumber'],
    relations: [{ field: 'internetDetails', targetTable: 'InternetContractDetails', type: 'one' }],
    foreignKeys: [{ field: 'internetContractDetailsId', targetTable: 'InternetContractDetails' }],
  },
  MobileContractDetails: {
    model: 'mobileContractDetails',
    primaryKey: 'id',
    readonlyFields: ['id'],
    requiredFields: ['contractId'],
    relations: [{ field: 'contract', targetTable: 'Contract', type: 'one' }],
    foreignKeys: [{ field: 'contractId', targetTable: 'Contract' }],
  },
  TvContractDetails: {
    model: 'tvContractDetails',
    primaryKey: 'id',
    readonlyFields: ['id'],
    requiredFields: ['contractId'],
    relations: [{ field: 'contract', targetTable: 'Contract', type: 'one' }],
    foreignKeys: [{ field: 'contractId', targetTable: 'Contract' }],
  },
  CarInsuranceDetails: {
    model: 'carInsuranceDetails',
    primaryKey: 'id',
    readonlyFields: ['id'],
    requiredFields: ['contractId'],
    relations: [{ field: 'contract', targetTable: 'Contract', type: 'one' }],
    foreignKeys: [{ field: 'contractId', targetTable: 'Contract' }],
  },
};

// Schema-Informationen abrufen
router.get(
  '/schema',
  authenticate,
  requirePermission('developer:access'),
  async (req: AuthRequest, res: Response) => {
    try {
      const tables = Object.entries(tableMetadata).map(([name, meta]) => ({
        name,
        ...meta,
      }));

      res.json({ success: true, data: tables });
    } catch (error) {
      console.error('Schema error:', error);
      res.status(500).json({ success: false, error: 'Fehler beim Laden des Schemas' });
    }
  }
);

// Tabellen-Daten abrufen
router.get(
  '/table/:tableName',
  authenticate,
  requirePermission('developer:access'),
  async (req: AuthRequest, res: Response) => {
    try {
      const { tableName } = req.params;
      const { page = '1', limit = '50' } = req.query;

      const meta = tableMetadata[tableName];
      if (!meta) {
        res.status(404).json({ success: false, error: 'Tabelle nicht gefunden' });
        return;
      }

      const skip = (parseInt(page as string) - 1) * parseInt(limit as string);
      const take = parseInt(limit as string);

      const model = (prisma as any)[meta.model];

      const [data, total] = await Promise.all([
        model.findMany({
          skip,
          take,
          orderBy: meta.primaryKey.includes(',') ? undefined : { [meta.primaryKey.split(',')[0]]: 'desc' },
        }),
        model.count(),
      ]);

      res.json({
        success: true,
        data,
        meta: {
          ...meta,
          tableName,
        },
        pagination: {
          page: parseInt(page as string),
          limit: parseInt(limit as string),
          total,
          totalPages: Math.ceil(total / parseInt(limit as string)),
        },
      });
    } catch (error) {
      console.error('Table data error:', error);
      res.status(500).json({ success: false, error: 'Fehler beim Laden der Daten' });
    }
  }
);

// Einzelne Zeile aktualisieren
router.put(
  '/table/:tableName/:id',
  authenticate,
  requirePermission('developer:access'),
  async (req: AuthRequest, res: Response) => {
    try {
      const { tableName, id } = req.params;
      const updates = req.body;

      const meta = tableMetadata[tableName];
      if (!meta) {
        res.status(404).json({ success: false, error: 'Tabelle nicht gefunden' });
        return;
      }

      // Readonly-Felder aus Updates entfernen
      const filteredUpdates: Record<string, any> = {};
      for (const [key, value] of Object.entries(updates)) {
        if (!meta.readonlyFields.includes(key)) {
          filteredUpdates[key] = value;
        }
      }

      // Prüfen ob required-Felder nicht auf null/leer gesetzt werden
      for (const field of meta.requiredFields) {
        if (field in filteredUpdates && (filteredUpdates[field] === null || filteredUpdates[field] === '')) {
          res.status(400).json({ success: false, error: `Feld '${field}' ist erforderlich` });
          return;
        }
      }

      const model = (prisma as any)[meta.model];

      // Composite Primary Key Handling
      let where: any;
      if (meta.primaryKey.includes(',')) {
        const keys = meta.primaryKey.split(',');
        const idParts = id.split('-');
        where = {};
        keys.forEach((key, idx) => {
          where[key] = parseInt(idParts[idx]);
        });
      } else {
        where = { [meta.primaryKey]: parseInt(id) };
      }

      const updated = await model.update({
        where,
        data: filteredUpdates,
      });

      res.json({ success: true, data: updated });
    } catch (error: any) {
      console.error('Update error:', error);
      if (error.code === 'P2003') {
        res.status(400).json({ success: false, error: 'Fremdschlüssel-Verletzung: Referenzierter Datensatz existiert nicht' });
      } else if (error.code === 'P2002') {
        res.status(400).json({ success: false, error: 'Unique-Constraint-Verletzung: Wert existiert bereits' });
      } else {
        res.status(500).json({ success: false, error: 'Fehler beim Aktualisieren' });
      }
    }
  }
);

// Zeile löschen (nur wenn keine abhängigen Daten)
router.delete(
  '/table/:tableName/:id',
  authenticate,
  requirePermission('developer:access'),
  async (req: AuthRequest, res: Response) => {
    try {
      const { tableName, id } = req.params;

      const meta = tableMetadata[tableName];
      if (!meta) {
        res.status(404).json({ success: false, error: 'Tabelle nicht gefunden' });
        return;
      }

      const model = (prisma as any)[meta.model];

      // Composite Primary Key Handling
      let where: any;
      if (meta.primaryKey.includes(',')) {
        const keys = meta.primaryKey.split(',');
        const idParts = id.split('-');
        where = {};
        keys.forEach((key, idx) => {
          where[key] = parseInt(idParts[idx]);
        });
      } else {
        where = { [meta.primaryKey]: parseInt(id) };
      }

      // Prüfen ob abhängige Daten existieren (nur "many"-Relations)
      const record = await model.findUnique({
        where,
        include: meta.relations
          .filter((r) => r.type === 'many')
          .reduce((acc, r) => ({ ...acc, [r.field]: { take: 1 } }), {}),
      });

      if (!record) {
        res.status(404).json({ success: false, error: 'Datensatz nicht gefunden' });
        return;
      }

      // Prüfen auf abhängige Daten
      for (const rel of meta.relations.filter((r) => r.type === 'many')) {
        if (record[rel.field] && record[rel.field].length > 0) {
          res.status(400).json({
            success: false,
            error: `Kann nicht gelöscht werden: Es existieren abhängige Daten in '${rel.targetTable}'`,
          });
          return;
        }
      }

      await model.delete({ where });

      res.json({ success: true });
    } catch (error: any) {
      console.error('Delete error:', error);
      if (error.code === 'P2003') {
        res.status(400).json({ success: false, error: 'Kann nicht gelöscht werden: Fremdschlüssel-Abhängigkeit' });
      } else {
        res.status(500).json({ success: false, error: 'Fehler beim Löschen' });
      }
    }
  }
);

// Referenzierte Daten für Dropdowns abrufen
router.get(
  '/reference/:tableName',
  authenticate,
  requirePermission('developer:access'),
  async (req: AuthRequest, res: Response) => {
    try {
      const { tableName } = req.params;
      const { search = '', limit = '50' } = req.query;

      const meta = tableMetadata[tableName];
      if (!meta) {
        res.status(404).json({ success: false, error: 'Tabelle nicht gefunden' });
        return;
      }

      const model = (prisma as any)[meta.model];

      const data = await model.findMany({
        take: parseInt(limit as string),
      });

      res.json({ success: true, data });
    } catch (error) {
      console.error('Reference error:', error);
      res.status(500).json({ success: false, error: 'Fehler beim Laden der Referenzdaten' });
    }
  }
);

export default router;
