import { DeletionRequestStatus } from '@prisma/client';
import prisma from '../lib/prisma.js';
import { getAuditLogsByDataSubject } from './audit.service.js';
import { getCustomerConsents, withdrawAllConsents } from './consent.service.js';
import PDFDocument from 'pdfkit';
import fs from 'fs';
import path from 'path';

export interface CreateDeletionRequestData {
  customerId: number;
  requestSource: string;
  requestedBy: string;
}

export interface ProcessDeletionRequestData {
  processedBy: string;
  action: 'complete' | 'partial' | 'reject';
  retentionReason?: string;
}

/**
 * Exportiert alle Daten eines Kunden (DSGVO Art. 15)
 */
export async function exportCustomerData(customerId: number) {
  const customer = await prisma.customer.findUnique({
    where: { id: customerId },
    include: {
      addresses: true,
      bankCards: {
        select: {
          id: true,
          accountHolder: true,
          iban: true,
          bic: true,
          bankName: true,
          isActive: true,
          createdAt: true,
        },
      },
      identityDocuments: {
        select: {
          id: true,
          type: true,
          documentNumber: true,
          issuingAuthority: true,
          issueDate: true,
          expiryDate: true,
          isActive: true,
          createdAt: true,
        },
      },
      meters: {
        include: {
          readings: true,
        },
      },
      contracts: {
        include: {
          address: true,
          billingAddress: true,
          provider: true,
          tariff: true,
          energyDetails: {
            include: { invoices: true },
          },
          internetDetails: {
            include: { phoneNumbers: true },
          },
          mobileDetails: {
            include: { simCards: true },
          },
          tvDetails: true,
          carInsuranceDetails: true,
          historyEntries: true,
          tasks: {
            include: { subtasks: true },
          },
        },
      },
      stressfreiEmails: {
        select: {
          id: true,
          email: true,
          platform: true,
          isActive: true,
          createdAt: true,
        },
      },
      consents: true,
    },
  });

  if (!customer) {
    throw new Error('Kunde nicht gefunden');
  }

  // Audit-Logs für diesen Kunden
  const accessLogs = await getAuditLogsByDataSubject(customerId);

  // Sensible Felder entfernen
  const exportData = {
    exportDate: new Date().toISOString(),
    dataSubject: {
      id: customer.id,
      customerNumber: customer.customerNumber,
      name: `${customer.firstName} ${customer.lastName}`,
    },
    personalData: {
      salutation: customer.salutation,
      firstName: customer.firstName,
      lastName: customer.lastName,
      companyName: customer.companyName,
      type: customer.type,
      birthDate: customer.birthDate,
      birthPlace: customer.birthPlace,
      email: customer.email,
      phone: customer.phone,
      mobile: customer.mobile,
      taxNumber: customer.taxNumber,
      portalEnabled: customer.portalEnabled,
      portalEmail: customer.portalEmail,
      portalLastLogin: customer.portalLastLogin,
      createdAt: customer.createdAt,
      updatedAt: customer.updatedAt,
    },
    addresses: customer.addresses,
    bankCards: customer.bankCards,
    identityDocuments: customer.identityDocuments,
    meters: customer.meters,
    contracts: customer.contracts.map((c) => ({
      ...c,
      // Sensible Daten entfernen
      portalPasswordEncrypted: undefined,
    })),
    emails: customer.stressfreiEmails,
    consents: customer.consents,
    accessHistory: accessLogs.map((log) => ({
      timestamp: log.createdAt,
      action: log.action,
      user: log.userEmail,
      resource: log.resourceType,
      ipAddress: log.ipAddress,
    })),
  };

  return exportData;
}

/**
 * Erstellt eine Löschanfrage
 */
export async function createDeletionRequest(data: CreateDeletionRequestData) {
  // Prüfen ob Kunde existiert
  const customer = await prisma.customer.findUnique({
    where: { id: data.customerId },
  });

  if (!customer) {
    throw new Error('Kunde nicht gefunden');
  }

  // Prüfen ob bereits eine offene Anfrage existiert
  const existingRequest = await prisma.dataDeletionRequest.findFirst({
    where: {
      customerId: data.customerId,
      status: { in: ['PENDING', 'IN_PROGRESS'] },
    },
  });

  if (existingRequest) {
    throw new Error('Es existiert bereits eine offene Löschanfrage für diesen Kunden');
  }

  return prisma.dataDeletionRequest.create({
    data: {
      customerId: data.customerId,
      requestSource: data.requestSource,
      requestedBy: data.requestedBy,
      status: 'PENDING',
    },
  });
}

/**
 * Holt alle Löschanfragen mit Paginierung
 */
export async function getDeletionRequests(params: {
  status?: DeletionRequestStatus;
  page?: number;
  limit?: number;
}) {
  const { status, page = 1, limit = 20 } = params;

  const where = status ? { status } : {};

  const [requests, total] = await Promise.all([
    prisma.dataDeletionRequest.findMany({
      where,
      orderBy: { requestedAt: 'desc' },
      skip: (page - 1) * limit,
      take: limit,
    }),
    prisma.dataDeletionRequest.count({ where }),
  ]);

  // Kundendaten hinzufügen
  const customerIds = requests.map((r) => r.customerId);
  const customers = await prisma.customer.findMany({
    where: { id: { in: customerIds } },
    select: {
      id: true,
      customerNumber: true,
      firstName: true,
      lastName: true,
    },
  });

  const customerMap = new Map(customers.map((c) => [c.id, c]));

  const requestsWithCustomer = requests.map((r) => ({
    ...r,
    customer: customerMap.get(r.customerId) || null,
  }));

  return {
    data: requestsWithCustomer,
    pagination: {
      page,
      limit,
      total,
      totalPages: Math.ceil(total / limit),
    },
  };
}

/**
 * Holt eine einzelne Löschanfrage
 */
export async function getDeletionRequest(id: number) {
  const request = await prisma.dataDeletionRequest.findUnique({
    where: { id },
  });

  if (!request) return null;

  const customer = await prisma.customer.findUnique({
    where: { id: request.customerId },
    select: {
      id: true,
      customerNumber: true,
      firstName: true,
      lastName: true,
      email: true,
    },
  });

  return { ...request, customer };
}

/**
 * Bearbeitet eine Löschanfrage
 */
export async function processDeletionRequest(
  requestId: number,
  data: ProcessDeletionRequestData
) {
  const request = await prisma.dataDeletionRequest.findUnique({
    where: { id: requestId },
  });

  if (!request) {
    throw new Error('Löschanfrage nicht gefunden');
  }

  if (request.status !== 'PENDING' && request.status !== 'IN_PROGRESS') {
    throw new Error('Diese Anfrage wurde bereits bearbeitet');
  }

  // Status auf IN_PROGRESS setzen
  await prisma.dataDeletionRequest.update({
    where: { id: requestId },
    data: { status: 'IN_PROGRESS' },
  });

  const customerId = request.customerId;
  const deletedData: Record<string, number> = {};
  const retainedData: Record<string, { count: number; reason: string }> = {};

  try {
    if (data.action === 'reject') {
      // Anfrage ablehnen
      return prisma.dataDeletionRequest.update({
        where: { id: requestId },
        data: {
          status: 'REJECTED',
          processedAt: new Date(),
          processedBy: data.processedBy,
          retentionReason: data.retentionReason,
        },
      });
    }

    // Einwilligungen widerrufen
    await withdrawAllConsents(customerId, data.processedBy);
    deletedData['consents'] = 1;

    // Verträge prüfen - aktive Verträge müssen behalten werden
    const contracts = await prisma.contract.findMany({
      where: { customerId },
    });

    const activeContracts = contracts.filter(
      (c) => c.status === 'ACTIVE' || c.status === 'PENDING'
    );

    if (activeContracts.length > 0) {
      retainedData['contracts'] = {
        count: activeContracts.length,
        reason: 'Aktive Verträge müssen für die Vertragserfüllung aufbewahrt werden',
      };
    }

    // Löschbare Daten anonymisieren (statt hart löschen)
    if (data.action === 'complete' && activeContracts.length === 0) {
      // Kunde vollständig anonymisieren
      await anonymizeCustomer(customerId);
      deletedData['customer'] = 1;
      deletedData['addresses'] = 1;
      deletedData['bankCards'] = 1;
      deletedData['identityDocuments'] = 1;
    } else {
      // Teilweise Löschung - nur optionale Daten
      const deletedAddresses = await prisma.address.deleteMany({
        where: { customerId, isDefault: false },
      });
      deletedData['addresses'] = deletedAddresses.count;

      // Inaktive Bankkarten löschen
      const deletedBankCards = await prisma.bankCard.deleteMany({
        where: { customerId, isActive: false },
      });
      deletedData['bankCards'] = deletedBankCards.count;

      // Inaktive Dokumente löschen
      const deletedDocs = await prisma.identityDocument.deleteMany({
        where: { customerId, isActive: false },
      });
      deletedData['identityDocuments'] = deletedDocs.count;
    }

    // Löschnachweis generieren
    const proofPath = await generateDeletionProof(requestId, customerId, deletedData, retainedData);

    // Anfrage abschließen
    const status = Object.keys(retainedData).length > 0 ? 'PARTIALLY_COMPLETED' : 'COMPLETED';

    return prisma.dataDeletionRequest.update({
      where: { id: requestId },
      data: {
        status,
        processedAt: new Date(),
        processedBy: data.processedBy,
        deletedData: JSON.stringify(deletedData),
        retainedData: JSON.stringify(retainedData),
        retentionReason: data.retentionReason,
        proofDocument: proofPath,
      },
    });
  } catch (error) {
    // Bei Fehler Status zurücksetzen
    await prisma.dataDeletionRequest.update({
      where: { id: requestId },
      data: { status: 'PENDING' },
    });
    throw error;
  }
}

/**
 * Anonymisiert Kundendaten (DSGVO-konform)
 */
async function anonymizeCustomer(customerId: number) {
  const anonymized = `[GELÖSCHT-${Date.now()}]`;

  await prisma.customer.update({
    where: { id: customerId },
    data: {
      firstName: anonymized,
      lastName: anonymized,
      salutation: null,
      companyName: null,
      birthDate: null,
      birthPlace: null,
      email: null,
      phone: null,
      mobile: null,
      taxNumber: null,
      notes: null,
      portalEnabled: false,
      portalEmail: null,
      portalPasswordHash: null,
      portalPasswordEncrypted: null,
    },
  });

  // Adressen anonymisieren
  await prisma.address.updateMany({
    where: { customerId },
    data: {
      street: anonymized,
      houseNumber: '',
      postalCode: '00000',
      city: anonymized,
    },
  });

  // Bankkarten anonymisieren
  await prisma.bankCard.updateMany({
    where: { customerId },
    data: {
      accountHolder: anonymized,
      iban: 'XX00000000000000000000',
      bic: null,
      bankName: null,
      isActive: false,
    },
  });

  // Ausweisdokumente anonymisieren
  await prisma.identityDocument.updateMany({
    where: { customerId },
    data: {
      documentNumber: anonymized,
      issuingAuthority: null,
      isActive: false,
    },
  });
}

/**
 * Generiert ein Löschnachweis-PDF
 */
async function generateDeletionProof(
  requestId: number,
  customerId: number,
  deletedData: Record<string, number>,
  retainedData: Record<string, { count: number; reason: string }>
): Promise<string> {
  const uploadsDir = path.join(process.cwd(), 'uploads', 'gdpr');

  // Verzeichnis erstellen falls nicht vorhanden
  if (!fs.existsSync(uploadsDir)) {
    fs.mkdirSync(uploadsDir, { recursive: true });
  }

  const filename = `loeschnachweis_${requestId}_${Date.now()}.pdf`;
  const filepath = path.join(uploadsDir, filename);

  const doc = new PDFDocument({ size: 'A4', margin: 50 });
  const writeStream = fs.createWriteStream(filepath);
  doc.pipe(writeStream);

  // Titel
  doc.fontSize(18).text('Datenlöschungsnachweis', { align: 'center' });
  doc.moveDown();

  // Metadaten
  doc.fontSize(12);
  doc.text(`Anfrage-ID: ${requestId}`);
  doc.text(`Kunden-ID: ${customerId}`);
  doc.text(`Datum: ${new Date().toLocaleDateString('de-DE')}`);
  doc.text(`Uhrzeit: ${new Date().toLocaleTimeString('de-DE')}`);
  doc.moveDown();

  // Gelöschte Daten
  doc.fontSize(14).text('Gelöschte Daten:', { underline: true });
  doc.fontSize(12);
  for (const [category, count] of Object.entries(deletedData)) {
    doc.text(`• ${category}: ${count} Einträge`);
  }
  doc.moveDown();

  // Aufbewahrte Daten
  if (Object.keys(retainedData).length > 0) {
    doc.fontSize(14).text('Aufbewahrte Daten:', { underline: true });
    doc.fontSize(12);
    for (const [category, info] of Object.entries(retainedData)) {
      doc.text(`• ${category}: ${info.count} Einträge`);
      doc.fontSize(10).text(`  Grund: ${info.reason}`, { indent: 20 });
      doc.fontSize(12);
    }
    doc.moveDown();
  }

  // Rechtlicher Hinweis
  doc.moveDown();
  doc.fontSize(10).text(
    'Dieses Dokument bestätigt die Durchführung der Datenlöschung gemäß Art. 17 DSGVO. ' +
    'Daten, die aus gesetzlichen Gründen aufbewahrt werden müssen, wurden nicht gelöscht.',
    { align: 'justify' }
  );

  doc.end();

  // Warten bis Datei geschrieben wurde
  await new Promise<void>((resolve) => writeStream.on('finish', resolve));

  return `gdpr/${filename}`;
}

/**
 * Dashboard-Statistiken für DSGVO
 */
export async function getGDPRDashboardStats() {
  const [
    pendingDeletions,
    completedDeletions,
    recentExports,
    consentStats,
  ] = await Promise.all([
    // Offene Löschanfragen
    prisma.dataDeletionRequest.count({
      where: { status: { in: ['PENDING', 'IN_PROGRESS'] } },
    }),
    // Abgeschlossene Löschungen (letzte 30 Tage)
    prisma.dataDeletionRequest.count({
      where: {
        status: { in: ['COMPLETED', 'PARTIALLY_COMPLETED'] },
        processedAt: { gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) },
      },
    }),
    // Letzte Datenexporte (aus Audit-Log)
    prisma.auditLog.count({
      where: {
        action: 'EXPORT',
        resourceType: 'GDPR',
        createdAt: { gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) },
      },
    }),
    // Consent-Statistik
    prisma.customerConsent.groupBy({
      by: ['status'],
      _count: { id: true },
    }),
  ]);

  const consentByStatus = consentStats.reduce(
    (acc, s) => {
      acc[s.status.toLowerCase()] = s._count.id;
      return acc;
    },
    { granted: 0, withdrawn: 0, pending: 0 } as Record<string, number>
  );

  return {
    deletionRequests: {
      pending: pendingDeletions,
      completedLast30Days: completedDeletions,
    },
    dataExports: {
      last30Days: recentExports,
    },
    consents: consentByStatus,
  };
}
