/**
 * RoPA (Records of Processing Activities) Export Utilities
 *
 * Functions for generating Art. 30(2) DSGVO compliant
 * processor-perspective records.
 */

import type {
  ProcessingActivity,
  Vendor,
  Organization,
  LocalizedText,
  ThirdCountryTransfer,
} from '../types'

// ==========================================
// TYPES
// ==========================================

export interface RoPAExportOptions {
  activities: ProcessingActivity[]
  vendors: Vendor[]
  organization: Organization
  language: 'de' | 'en'
  format: 'PDF' | 'DOCX' | 'XLSX'
  includeSubProcessors?: boolean
  includeTransfers?: boolean
}

export interface RoPARow {
  // Art. 30(2)(a) - Controller info
  controllerName: string
  controllerAddress: string
  controllerDPO: string

  // Art. 30(2)(b) - Processing categories
  processingCategories: string[]

  // Art. 30(2)(c) - Third country transfers
  thirdCountryTransfers: string[]
  transferMechanisms: string[]

  // Art. 30(2)(d) - Technical measures (general description)
  technicalMeasures: string[]

  // Additional info
  subProcessors: string[]
  status: string
}

export interface RoPAExportResult {
  success: boolean
  filename: string
  mimeType: string
  content: string
  metadata: {
    controllerCount: number
    processingCount: number
    generatedAt: Date
    language: string
    processorName: string
  }
}

// ==========================================
// HELPER FUNCTIONS
// ==========================================

function getLocalizedText(text: LocalizedText | undefined, lang: 'de' | 'en'): string {
  if (!text) return ''
  return text[lang] || text.de || ''
}

function formatTransfers(transfers: ThirdCountryTransfer[], lang: 'de' | 'en'): string[] {
  const mechanismLabels: Record<string, LocalizedText> = {
    ADEQUACY_DECISION: { de: 'Angemessenheitsbeschluss', en: 'Adequacy Decision' },
    SCC_CONTROLLER: { de: 'SCC (C2C)', en: 'SCC (C2C)' },
    SCC_PROCESSOR: { de: 'SCC (C2P)', en: 'SCC (C2P)' },
    BCR: { de: 'Binding Corporate Rules', en: 'Binding Corporate Rules' },
    DEROGATION_CONSENT: { de: 'Ausdrückliche Einwilligung', en: 'Explicit Consent' },
    DEROGATION_CONTRACT: { de: 'Vertragserfüllung', en: 'Contract Performance' },
    CERTIFICATION: { de: 'Zertifizierung', en: 'Certification' },
  }

  return transfers.map((t) => {
    const mechanism = mechanismLabels[t.transferMechanism]?.[lang] || t.transferMechanism
    return `${t.country}: ${t.recipient} (${mechanism})`
  })
}

function formatAddress(address: { street?: string; city?: string; postalCode?: string; country?: string }): string {
  if (!address) return '-'
  const parts = [address.street, address.postalCode, address.city, address.country].filter(Boolean)
  return parts.join(', ') || '-'
}

// ==========================================
// EXPORT FUNCTIONS
// ==========================================

/**
 * Transform activities to RoPA rows from processor perspective
 * Groups by controller (responsible party)
 */
export function transformToRoPARows(
  activities: ProcessingActivity[],
  vendors: Vendor[],
  lang: 'de' | 'en'
): RoPARow[] {
  // Group activities by controller
  const byController = new Map<string, ProcessingActivity[]>()

  for (const activity of activities) {
    const controllerName = activity.responsible.organizationName
    if (!byController.has(controllerName)) {
      byController.set(controllerName, [])
    }
    byController.get(controllerName)!.push(activity)
  }

  // Transform to RoPA rows
  const rows: RoPARow[] = []

  for (const [controllerName, controllerActivities] of byController) {
    const firstActivity = controllerActivities[0]

    // Collect all processing categories
    const processingCategories = controllerActivities.map((a) =>
      getLocalizedText(a.name, lang)
    )

    // Collect all third country transfers
    const allTransfers = controllerActivities.flatMap((a) => a.thirdCountryTransfers)
    const uniqueTransfers = formatTransfers(
      allTransfers.filter(
        (t, i, arr) => arr.findIndex((x) => x.country === t.country && x.recipient === t.recipient) === i
      ),
      lang
    )

    // Collect unique transfer mechanisms
    const uniqueMechanisms = [...new Set(allTransfers.map((t) => t.transferMechanism))]

    // Collect all TOM references
    const allTOM = [...new Set(controllerActivities.flatMap((a) => a.technicalMeasures))]

    // Collect sub-processors from vendors
    const subProcessorIds = [...new Set(controllerActivities.flatMap((a) => a.subProcessors))]
    const subProcessorNames = subProcessorIds
      .map((id) => vendors.find((v) => v.id === id)?.name)
      .filter((name): name is string => !!name)

    // DPO contact
    const dpoContact = firstActivity.dpoContact
      ? `${firstActivity.dpoContact.name} (${firstActivity.dpoContact.email})`
      : firstActivity.responsible.contact
      ? `${firstActivity.responsible.contact.name} (${firstActivity.responsible.contact.email})`
      : '-'

    rows.push({
      controllerName,
      controllerAddress: formatAddress(firstActivity.responsible.address),
      controllerDPO: dpoContact,
      processingCategories,
      thirdCountryTransfers: uniqueTransfers,
      transferMechanisms: uniqueMechanisms,
      technicalMeasures: allTOM,
      subProcessors: subProcessorNames,
      status: controllerActivities.every((a) => a.status === 'APPROVED') ? 'APPROVED' : 'PENDING',
    })
  }

  return rows
}

/**
 * Generate RoPA as JSON
 */
export function generateRoPAJson(options: RoPAExportOptions): RoPAExportResult {
  const rows = transformToRoPARows(options.activities, options.vendors, options.language)

  const exportData = {
    metadata: {
      processor: {
        name: options.organization.name,
        address: formatAddress(options.organization.address),
        dpo: options.organization.dpoContact
          ? `${options.organization.dpoContact.name} (${options.organization.dpoContact.email})`
          : '-',
      },
      generatedAt: new Date().toISOString(),
      language: options.language,
      gdprArticle: 'Art. 30(2) DSGVO',
      version: '1.0',
    },
    records: rows.map((row, index) => ({
      recordNumber: index + 1,
      ...row,
    })),
    summary: {
      controllerCount: rows.length,
      totalProcessingCategories: rows.reduce((sum, r) => sum + r.processingCategories.length, 0),
      withThirdCountryTransfers: rows.filter((r) => r.thirdCountryTransfers.length > 0).length,
      uniqueSubProcessors: [...new Set(rows.flatMap((r) => r.subProcessors))].length,
    },
  }

  const content = JSON.stringify(exportData, null, 2)

  return {
    success: true,
    filename: `RoPA_${options.organization.name.replace(/\s+/g, '_')}_${new Date().toISOString().slice(0, 10)}.json`,
    mimeType: 'application/json',
    content,
    metadata: {
      controllerCount: rows.length,
      processingCount: options.activities.length,
      generatedAt: new Date(),
      language: options.language,
      processorName: options.organization.name,
    },
  }
}

/**
 * Generate RoPA as CSV
 */
export function generateRoPACsv(options: RoPAExportOptions): string {
  const rows = transformToRoPARows(options.activities, options.vendors, options.language)
  const lang = options.language

  const headers =
    lang === 'de'
      ? [
          'Nr.',
          'Verantwortlicher',
          'Anschrift',
          'DSB',
          'Verarbeitungskategorien',
          'Drittlandtransfers',
          'Transfermechanismen',
          'TOM',
          'Unterauftragnehmer',
          'Status',
        ]
      : [
          'No.',
          'Controller',
          'Address',
          'DPO',
          'Processing Categories',
          'Third Country Transfers',
          'Transfer Mechanisms',
          'Technical Measures',
          'Sub-Processors',
          'Status',
        ]

  const csvRows = rows.map((row, index) => [
    (index + 1).toString(),
    row.controllerName,
    row.controllerAddress,
    row.controllerDPO,
    row.processingCategories.join('; '),
    row.thirdCountryTransfers.join('; '),
    row.transferMechanisms.join('; '),
    row.technicalMeasures.join('; '),
    row.subProcessors.join('; '),
    row.status,
  ])

  const escape = (val: string) => `"${val.replace(/"/g, '""')}"`

  return [
    headers.map(escape).join(','),
    ...csvRows.map((row) => row.map(escape).join(',')),
  ].join('\n')
}

/**
 * Generate processor summary for RoPA
 */
export function generateProcessorSummary(
  activities: ProcessingActivity[],
  vendors: Vendor[],
  lang: 'de' | 'en'
): {
  totalControllers: number
  totalCategories: number
  withTransfers: number
  subProcessorCount: number
  pendingApproval: number
} {
  const rows = transformToRoPARows(activities, vendors, lang)

  return {
    totalControllers: rows.length,
    totalCategories: rows.reduce((sum, r) => sum + r.processingCategories.length, 0),
    withTransfers: rows.filter((r) => r.thirdCountryTransfers.length > 0).length,
    subProcessorCount: [...new Set(rows.flatMap((r) => r.subProcessors))].length,
    pendingApproval: rows.filter((r) => r.status !== 'APPROVED').length,
  }
}

/**
 * Validate RoPA completeness
 */
export function validateRoPACompleteness(
  rows: RoPARow[],
  lang: 'de' | 'en'
): { isComplete: boolean; issues: string[] } {
  const issues: string[] = []

  for (const row of rows) {
    // Art. 30(2)(a) - Controller info
    if (!row.controllerName) {
      issues.push(
        lang === 'de'
          ? 'Name des Verantwortlichen fehlt'
          : 'Controller name missing'
      )
    }

    // Art. 30(2)(b) - Processing categories
    if (row.processingCategories.length === 0) {
      issues.push(
        lang === 'de'
          ? `${row.controllerName}: Keine Verarbeitungskategorien angegeben`
          : `${row.controllerName}: No processing categories specified`
      )
    }

    // Art. 30(2)(c) - Transfers without mechanism
    if (row.thirdCountryTransfers.length > 0 && row.transferMechanisms.length === 0) {
      issues.push(
        lang === 'de'
          ? `${row.controllerName}: Drittlandtransfer ohne Rechtsgrundlage`
          : `${row.controllerName}: Third country transfer without legal basis`
      )
    }

    // Art. 30(2)(d) - TOM
    if (row.technicalMeasures.length === 0) {
      issues.push(
        lang === 'de'
          ? `${row.controllerName}: Keine TOM angegeben`
          : `${row.controllerName}: No technical measures specified`
      )
    }
  }

  return {
    isComplete: issues.length === 0,
    issues,
  }
}
