// =============================================================================
// Obligations Module - Compliance Check Engine
// Prueft Pflichten auf Vollstaendigkeit, Konsistenz und Auditfaehigkeit
// =============================================================================

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

export interface Obligation {
  id: string
  title: string
  description: string
  source: string
  source_article: string
  deadline: string | null
  status: 'pending' | 'in-progress' | 'completed' | 'overdue'
  priority: 'critical' | 'high' | 'medium' | 'low'
  responsible: string
  linked_systems: string[]
  linked_vendor_ids?: string[]
  assessment_id?: string
  rule_code?: string
  notes?: string
  created_at?: string
  updated_at?: string
  evidence?: string[]
  review_date?: string
  category?: string
}

export type ObligationComplianceIssueType =
  | 'MISSING_RESPONSIBLE'
  | 'OVERDUE_DEADLINE'
  | 'MISSING_EVIDENCE'
  | 'MISSING_DESCRIPTION'
  | 'NO_LEGAL_REFERENCE'
  | 'INCOMPLETE_REGULATION'
  | 'HIGH_PRIORITY_NOT_STARTED'
  | 'STALE_PENDING'
  | 'MISSING_LINKED_SYSTEMS'
  | 'NO_REVIEW_PROCESS'
  | 'CRITICAL_WITHOUT_EVIDENCE'
  | 'MISSING_VENDOR_LINK'

export type ObligationComplianceIssueSeverity = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW'

export interface ObligationComplianceIssue {
  type: ObligationComplianceIssueType
  severity: ObligationComplianceIssueSeverity
  message: string
  affectedObligations: string[]
  recommendation: string
}

export interface ObligationComplianceCheckResult {
  score: number
  issues: ObligationComplianceIssue[]
  summary: { total: number; critical: number; high: number; medium: number; low: number }
  checkedAt: string
}

// =============================================================================
// CONSTANTS
// =============================================================================

export const OBLIGATION_SEVERITY_LABELS_DE: Record<ObligationComplianceIssueSeverity, string> = {
  CRITICAL: 'Kritisch',
  HIGH: 'Hoch',
  MEDIUM: 'Mittel',
  LOW: 'Niedrig',
}

export const OBLIGATION_SEVERITY_COLORS: Record<ObligationComplianceIssueSeverity, string> = {
  CRITICAL: '#dc2626',
  HIGH: '#ea580c',
  MEDIUM: '#d97706',
  LOW: '#6b7280',
}

// =============================================================================
// HELPERS
// =============================================================================

function daysBetween(date: Date, now: Date): number {
  const diffMs = now.getTime() - date.getTime()
  return Math.floor(diffMs / (1000 * 60 * 60 * 24))
}

// =============================================================================
// PER-OBLIGATION CHECKS (1-5, 9, 11)
// =============================================================================

/**
 * Check 1: MISSING_RESPONSIBLE (MEDIUM)
 * Pflicht ohne verantwortliche Person/Abteilung.
 */
function checkMissingResponsible(obligations: Obligation[]): ObligationComplianceIssue | null {
  const affected = obligations.filter(o => !o.responsible || o.responsible.trim() === '')
  if (affected.length === 0) return null

  return {
    type: 'MISSING_RESPONSIBLE',
    severity: 'MEDIUM',
    message: `${affected.length} Pflicht(en) ohne verantwortliche Person oder Abteilung. Ohne klare Zustaendigkeit koennen Pflichten nicht zuverlaessig umgesetzt werden.`,
    affectedObligations: affected.map(o => o.id),
    recommendation: 'Weisen Sie jeder Pflicht eine verantwortliche Person oder Abteilung zu.',
  }
}

/**
 * Check 2: OVERDUE_DEADLINE (HIGH)
 * Pflicht mit Deadline in der Vergangenheit + Status != completed.
 */
function checkOverdueDeadline(obligations: Obligation[]): ObligationComplianceIssue | null {
  const now = new Date()
  const affected = obligations.filter(o => {
    if (!o.deadline || o.status === 'completed') return false
    return new Date(o.deadline) < now
  })
  if (affected.length === 0) return null

  return {
    type: 'OVERDUE_DEADLINE',
    severity: 'HIGH',
    message: `${affected.length} Pflicht(en) mit ueberschrittener Frist. Ueberfaellige Pflichten stellen ein Compliance-Risiko dar und koennen zu Bussgeldern fuehren.`,
    affectedObligations: affected.map(o => o.id),
    recommendation: 'Bearbeiten Sie ueberfaellige Pflichten umgehend oder passen Sie die Fristen an.',
  }
}

/**
 * Check 3: MISSING_EVIDENCE (HIGH)
 * Completed-Pflicht ohne Evidence.
 */
function checkMissingEvidence(obligations: Obligation[]): ObligationComplianceIssue | null {
  const affected = obligations.filter(o =>
    o.status === 'completed' && (!o.evidence || o.evidence.length === 0)
  )
  if (affected.length === 0) return null

  return {
    type: 'MISSING_EVIDENCE',
    severity: 'HIGH',
    message: `${affected.length} abgeschlossene Pflicht(en) ohne Nachweis. Ohne Nachweise ist die Erfuellung im Audit nicht belegbar.`,
    affectedObligations: affected.map(o => o.id),
    recommendation: 'Hinterlegen Sie Nachweisdokumente fuer alle abgeschlossenen Pflichten.',
  }
}

/**
 * Check 4: MISSING_DESCRIPTION (MEDIUM)
 * Pflicht ohne Beschreibung.
 */
function checkMissingDescription(obligations: Obligation[]): ObligationComplianceIssue | null {
  const affected = obligations.filter(o => !o.description || o.description.trim() === '')
  if (affected.length === 0) return null

  return {
    type: 'MISSING_DESCRIPTION',
    severity: 'MEDIUM',
    message: `${affected.length} Pflicht(en) ohne Beschreibung. Eine fehlende Beschreibung erschwert die Nachvollziehbarkeit und Umsetzung.`,
    affectedObligations: affected.map(o => o.id),
    recommendation: 'Ergaenzen Sie eine Beschreibung fuer jede Pflicht, die den Inhalt und die Anforderungen erlaeutert.',
  }
}

/**
 * Check 5: NO_LEGAL_REFERENCE (HIGH)
 * Pflicht ohne source_article (kein Artikel-Bezug).
 */
function checkNoLegalReference(obligations: Obligation[]): ObligationComplianceIssue | null {
  const affected = obligations.filter(o => !o.source_article || o.source_article.trim() === '')
  if (affected.length === 0) return null

  return {
    type: 'NO_LEGAL_REFERENCE',
    severity: 'HIGH',
    message: `${affected.length} Pflicht(en) ohne Artikel-/Paragraphen-Referenz. Ohne Rechtsbezug ist die Pflicht im Audit nicht nachvollziehbar.`,
    affectedObligations: affected.map(o => o.id),
    recommendation: 'Ergaenzen Sie die Rechtsgrundlage (z.B. Art. 32 DSGVO) fuer jede Pflicht.',
  }
}

/**
 * Check 9: MISSING_LINKED_SYSTEMS (MEDIUM)
 * Pflicht ohne verknuepfte Systeme/Verarbeitungen.
 */
function checkMissingLinkedSystems(obligations: Obligation[]): ObligationComplianceIssue | null {
  const affected = obligations.filter(o => !o.linked_systems || o.linked_systems.length === 0)
  if (affected.length === 0) return null

  return {
    type: 'MISSING_LINKED_SYSTEMS',
    severity: 'MEDIUM',
    message: `${affected.length} Pflicht(en) ohne verknuepfte Systeme oder Verarbeitungstaetigkeiten. Ohne Systemzuordnung fehlt der operative Bezug.`,
    affectedObligations: affected.map(o => o.id),
    recommendation: 'Ordnen Sie jeder Pflicht die betroffenen IT-Systeme oder Verarbeitungstaetigkeiten zu.',
  }
}

/**
 * Check 11: CRITICAL_WITHOUT_EVIDENCE (CRITICAL)
 * Critical-Pflicht ohne Evidence.
 */
function checkCriticalWithoutEvidence(obligations: Obligation[]): ObligationComplianceIssue | null {
  const affected = obligations.filter(o =>
    o.priority === 'critical' && (!o.evidence || o.evidence.length === 0)
  )
  if (affected.length === 0) return null

  return {
    type: 'CRITICAL_WITHOUT_EVIDENCE',
    severity: 'CRITICAL',
    message: `${affected.length} kritische Pflicht(en) ohne Nachweis. Kritische Pflichten erfordern zwingend eine Dokumentation der Erfuellung.`,
    affectedObligations: affected.map(o => o.id),
    recommendation: 'Hinterlegen Sie umgehend Nachweise fuer alle kritischen Pflichten.',
  }
}

/**
 * Check 12: MISSING_VENDOR_LINK (MEDIUM)
 * Art.-28-Pflicht ohne verknuepften Auftragsverarbeiter.
 */
function checkMissingVendorLink(obligations: Obligation[]): ObligationComplianceIssue | null {
  const affected = obligations.filter(o =>
    o.source_article?.includes('Art. 28') &&
    (!o.linked_vendor_ids || o.linked_vendor_ids.length === 0)
  )
  if (affected.length === 0) return null
  return {
    type: 'MISSING_VENDOR_LINK',
    severity: 'MEDIUM',
    message: `${affected.length} Art.-28-Pflicht(en) ohne verknuepften Auftragsverarbeiter.`,
    affectedObligations: affected.map(o => o.id),
    recommendation: 'Verknuepfen Sie Art.-28-Pflichten mit den betroffenen Auftragsverarbeitern im Vendor Register.',
  }
}

// =============================================================================
// AGGREGATE CHECKS (6-8, 10)
// =============================================================================

/**
 * Check 6: INCOMPLETE_REGULATION (HIGH)
 * Regulierung, bei der alle Pflichten pending/overdue sind.
 */
function checkIncompleteRegulation(obligations: Obligation[]): ObligationComplianceIssue | null {
  const bySource = new Map<string, Obligation[]>()
  for (const o of obligations) {
    const src = o.source || 'Unbekannt'
    if (!bySource.has(src)) bySource.set(src, [])
    bySource.get(src)!.push(o)
  }

  const incompleteRegs: string[] = []
  const affectedIds: string[] = []

  for (const [source, obls] of bySource.entries()) {
    if (obls.length < 2) continue // Skip single-obligation regulations
    const allStalled = obls.every(o => o.status === 'pending' || o.status === 'overdue')
    if (allStalled) {
      incompleteRegs.push(source)
      affectedIds.push(...obls.map(o => o.id))
    }
  }

  if (incompleteRegs.length === 0) return null

  return {
    type: 'INCOMPLETE_REGULATION',
    severity: 'HIGH',
    message: `${incompleteRegs.length} Regulierung(en) vollstaendig ohne Umsetzung: ${incompleteRegs.join(', ')}. Alle Pflichten sind ausstehend oder ueberfaellig.`,
    affectedObligations: affectedIds,
    recommendation: 'Beginnen Sie mit der Umsetzung der wichtigsten Pflichten in den betroffenen Regulierungen.',
  }
}

/**
 * Check 7: HIGH_PRIORITY_NOT_STARTED (CRITICAL)
 * Critical/High-Pflicht seit > 30 Tagen pending.
 */
function checkHighPriorityNotStarted(obligations: Obligation[]): ObligationComplianceIssue | null {
  const now = new Date()
  const affected = obligations.filter(o => {
    if (o.status !== 'pending') return false
    if (o.priority !== 'critical' && o.priority !== 'high') return false
    if (!o.created_at) return false
    return daysBetween(new Date(o.created_at), now) > 30
  })

  if (affected.length === 0) return null

  return {
    type: 'HIGH_PRIORITY_NOT_STARTED',
    severity: 'CRITICAL',
    message: `${affected.length} hochprioritaere Pflicht(en) seit ueber 30 Tagen nicht begonnen. Dies deutet auf organisatorische Blockaden oder fehlende Priorisierung hin.`,
    affectedObligations: affected.map(o => o.id),
    recommendation: 'Starten Sie umgehend mit der Bearbeitung dieser kritischen/hohen Pflichten und erstellen Sie einen Umsetzungsplan.',
  }
}

/**
 * Check 8: STALE_PENDING (LOW)
 * Pflicht seit > 90 Tagen pending.
 */
function checkStalePending(obligations: Obligation[]): ObligationComplianceIssue | null {
  const now = new Date()
  const affected = obligations.filter(o => {
    if (o.status !== 'pending') return false
    if (!o.created_at) return false
    return daysBetween(new Date(o.created_at), now) > 90
  })

  if (affected.length === 0) return null

  return {
    type: 'STALE_PENDING',
    severity: 'LOW',
    message: `${affected.length} Pflicht(en) seit ueber 90 Tagen ausstehend. Langfristig unbearbeitete Pflichten sollten priorisiert oder als nicht relevant markiert werden.`,
    affectedObligations: affected.map(o => o.id),
    recommendation: 'Pruefen Sie, ob die Pflichten weiterhin relevant sind, und setzen Sie Prioritaeten fuer die Umsetzung.',
  }
}

/**
 * Check 10: NO_REVIEW_PROCESS (MEDIUM)
 * Keine einzige Pflicht hat review_date.
 */
function checkNoReviewProcess(obligations: Obligation[]): ObligationComplianceIssue | null {
  if (obligations.length === 0) return null
  const hasAnyReview = obligations.some(o => o.review_date)
  if (hasAnyReview) return null

  return {
    type: 'NO_REVIEW_PROCESS',
    severity: 'MEDIUM',
    message: 'Keine Pflicht hat ein Pruefungsdatum (review_date). Ohne regelmaessige Ueberpruefung ist die Aktualitaet des Pflichtenregisters nicht gewaehrleistet.',
    affectedObligations: [],
    recommendation: 'Fuehren Sie ein Pruefintervall ein und setzen Sie review_date fuer alle Pflichten.',
  }
}

// =============================================================================
// MAIN COMPLIANCE CHECK
// =============================================================================

/**
 * Fuehrt einen vollstaendigen Compliance-Check ueber alle Pflichten durch.
 */
export function runObligationComplianceCheck(obligations: Obligation[]): ObligationComplianceCheckResult {
  const issues: ObligationComplianceIssue[] = []

  const checks = [
    checkMissingResponsible(obligations),
    checkOverdueDeadline(obligations),
    checkMissingEvidence(obligations),
    checkMissingDescription(obligations),
    checkNoLegalReference(obligations),
    checkIncompleteRegulation(obligations),
    checkHighPriorityNotStarted(obligations),
    checkStalePending(obligations),
    checkMissingLinkedSystems(obligations),
    checkNoReviewProcess(obligations),
    checkCriticalWithoutEvidence(obligations),
    checkMissingVendorLink(obligations),
  ]

  for (const issue of checks) {
    if (issue !== null) {
      issues.push(issue)
    }
  }

  // Calculate score
  const summary = { total: issues.length, critical: 0, high: 0, medium: 0, low: 0 }
  for (const issue of issues) {
    switch (issue.severity) {
      case 'CRITICAL': summary.critical++; break
      case 'HIGH': summary.high++; break
      case 'MEDIUM': summary.medium++; break
      case 'LOW': summary.low++; break
    }
  }

  const rawScore = 100 - (summary.critical * 15 + summary.high * 10 + summary.medium * 5 + summary.low * 2)
  const score = Math.max(0, rawScore)

  return {
    score,
    issues,
    summary,
    checkedAt: new Date().toISOString(),
  }
}
