/**
 * Datenbank-Backup Script
 *
 * Exportiert ALLE Daten als JSON-Dateien für die Wiederherstellung nach Migrationen.
 *
 * Verwendung:
 *   npm run db:backup
 *
 * Erstellt einen Ordner 'prisma/backups/YYYY-MM-DDTHH-mm-ss/' mit JSON-Dateien pro Tabelle.
 *
 * Die Tabellen sind nach Abhängigkeitsreihenfolge sortiert (Level 0 = keine FKs, dann aufsteigend).
 * Damit kann das Restore-Script sie in der gleichen Reihenfolge einspielen, ohne FK-Verletzungen.
 */

import { PrismaClient } from '@prisma/client';
import * as fs from 'fs';
import * as path from 'path';

const prisma = new PrismaClient();

async function main() {
  // Backup-Ordner mit Zeitstempel erstellen
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
  const backupDir = path.join(__dirname, 'backups', timestamp);

  if (!fs.existsSync(backupDir)) {
    fs.mkdirSync(backupDir, { recursive: true });
  }

  console.log(`\n📦 Starte Datenbank-Backup nach: ${backupDir}\n`);

  // Tabellen in Abhängigkeitsreihenfolge (unabhängige zuerst)
  const tables = [
    // ============ Level 0: Reine Stammdaten/Kataloge ============
    { name: 'Permission', query: () => prisma.permission.findMany() },
    { name: 'Role', query: () => prisma.role.findMany() },
    { name: 'SalesPlatform', query: () => prisma.salesPlatform.findMany() },
    { name: 'ContractCategory', query: () => prisma.contractCategory.findMany() },
    { name: 'CancellationPeriod', query: () => prisma.cancellationPeriod.findMany() },
    { name: 'ContractDuration', query: () => prisma.contractDuration.findMany() },
    { name: 'AppSetting', query: () => prisma.appSetting.findMany() },
    { name: 'EmailProviderConfig', query: () => prisma.emailProviderConfig.findMany() },
    { name: 'Provider', query: () => prisma.provider.findMany() },
    { name: 'PdfTemplate', query: () => prisma.pdfTemplate.findMany() },
    { name: 'AuditRetentionPolicy', query: () => prisma.auditRetentionPolicy.findMany() },

    // ============ Level 1: Abhängig von Level 0 ============
    { name: 'RolePermission', query: () => prisma.rolePermission.findMany() },
    { name: 'User', query: () => prisma.user.findMany() },
    { name: 'Customer', query: () => prisma.customer.findMany() },
    { name: 'Tariff', query: () => prisma.tariff.findMany() },

    // ============ Level 2: Abhängig von Customer ============
    { name: 'UserRole', query: () => prisma.userRole.findMany() },
    { name: 'Address', query: () => prisma.address.findMany() },
    { name: 'BankCard', query: () => prisma.bankCard.findMany() },
    { name: 'IdentityDocument', query: () => prisma.identityDocument.findMany() },
    { name: 'Meter', query: () => prisma.meter.findMany() },
    { name: 'StressfreiEmail', query: () => prisma.stressfreiEmail.findMany() },
    { name: 'CustomerRepresentative', query: () => prisma.customerRepresentative.findMany() },
    { name: 'CustomerConsent', query: () => prisma.customerConsent.findMany() },
    { name: 'DataDeletionRequest', query: () => prisma.dataDeletionRequest.findMany() },

    // ============ Level 3: Contracts + abhängige ============
    { name: 'Contract', query: () => prisma.contract.findMany() },
    { name: 'RepresentativeAuthorization', query: () => prisma.representativeAuthorization.findMany() },

    // ============ Level 4: Vertragstyp-Details + Sub-Tabellen ============
    { name: 'EnergyContractDetails', query: () => prisma.energyContractDetails.findMany() },
    { name: 'InternetContractDetails', query: () => prisma.internetContractDetails.findMany() },
    { name: 'MobileContractDetails', query: () => prisma.mobileContractDetails.findMany() },
    { name: 'TvContractDetails', query: () => prisma.tvContractDetails.findMany() },
    { name: 'CarInsuranceDetails', query: () => prisma.carInsuranceDetails.findMany() },
    { name: 'ContractMeter', query: () => prisma.contractMeter.findMany() },
    { name: 'ContractDocument', query: () => prisma.contractDocument.findMany() },
    { name: 'ContractHistoryEntry', query: () => prisma.contractHistoryEntry.findMany() },
    { name: 'ContractTask', query: () => prisma.contractTask.findMany() },
    { name: 'Invoice', query: () => prisma.invoice.findMany() },
    { name: 'MeterReading', query: () => prisma.meterReading.findMany() },

    // ============ Level 5: Sub-Tabellen der Sub-Tabellen ============
    { name: 'ContractTaskSubtask', query: () => prisma.contractTaskSubtask.findMany() },
    { name: 'PhoneNumber', query: () => prisma.phoneNumber.findMany() },
    { name: 'SimCard', query: () => prisma.simCard.findMany() },

    // ============ Level 6: Logs & Emails (wachsende Tabellen) ============
    { name: 'CachedEmail', query: () => prisma.cachedEmail.findMany() },
    { name: 'EmailLog', query: () => prisma.emailLog.findMany() },
    { name: 'AuditLog', query: () => prisma.auditLog.findMany() },
  ];

  let totalRecords = 0;
  const stats: { table: string; count: number }[] = [];
  const skipped: string[] = [];

  for (const table of tables) {
    try {
      const data = await table.query();
      const count = data.length;
      totalRecords += count;
      stats.push({ table: table.name, count });

      // JSON-Datei schreiben (Date-Felder als ISO-String)
      const filePath = path.join(backupDir, `${table.name}.json`);
      fs.writeFileSync(filePath, JSON.stringify(data, null, 2));

      const status = count > 0 ? '✅' : '⚪';
      console.log(`${status} ${table.name}: ${count} Einträge`);
    } catch (error: any) {
      // Tabelle existiert möglicherweise nicht (bei älteren Schema-Versionen)
      skipped.push(table.name);
      console.log(`⚠️  ${table.name}: Übersprungen (${error.message?.slice(0, 80)}...)`);
    }
  }

  // Backup-Info speichern
  const backupInfo = {
    timestamp: new Date().toISOString(),
    schemaVersion: 'current',
    totalRecords,
    tables: stats,
    skippedTables: skipped,
  };
  fs.writeFileSync(path.join(backupDir, '_backup-info.json'), JSON.stringify(backupInfo, null, 2));

  console.log(`\n✅ Backup abgeschlossen!`);
  console.log(`   📊 ${totalRecords} Datensätze in ${stats.filter(s => s.count > 0).length} Tabellen`);
  if (skipped.length > 0) {
    console.log(`   ⚠️  ${skipped.length} Tabellen übersprungen: ${skipped.join(', ')}`);
  }
  console.log(`   📁 Gespeichert in: ${backupDir}\n`);
}

main()
  .catch((e) => {
    console.error('❌ Backup fehlgeschlagen:', e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
