// QAF Root-Cause engine (KAR-799, spec B8).
//
// Deterministic, data-based, reproducible — NO free AI generation. Ranks the
// biggest absolute and relative cost drivers, separates structure and currency
// effects, and produces a 2–4 sentence management summary built ONLY from the
// computed deltas. Net-new. Pure.

import type { QAFRow } from '@/lib/qaf-parser'
import type { FieldDiff, MatchStatus } from './types'

export interface StepDiffSummary {
  stepLabel: string
  matchStatus: MatchStatus
  fieldDiffs: FieldDiff[]
}

export interface RootCauseInput {
  partNumber: string | null
  /** Matched steps with their per-field diffs. */
  steps: StepDiffSummary[]
  newSteps: string[]
  removedSteps: string[]
  /** Labels of steps flagged possible_structure_change. */
  structureChangeSteps: string[]
  currencyChanged: boolean
}

export interface RootCauseDriver {
  stepLabel: string
  field: keyof QAFRow
  deltaAbsolute: number
  deltaPercent: number | null
}

export interface RootCauseResult {
  partNumber: string | null
  topAbsoluteDrivers: RootCauseDriver[]
  topRelativeDrivers: RootCauseDriver[]
  structureChanges: { new: string[]; removed: string[]; possible: string[] }
  currencyEffect: boolean
  managementSummary: string
  requiresReviewNote: boolean
}

/** Result-cost fields that count as cost "drivers" (spec B8 Ergebnis-Kosten). */
const RESULT_COST_FIELDS = new Set<keyof QAFRow>([
  'fk',
  'fkAW',
  'fek',
  'rfgk',
  'ruestkosten',
  'ausschusskosten',
  'lohnkosten',
  'mss',
])

const TOP_N = 3

function fmt(n: number): string {
  return Number(n.toFixed(2)).toString()
}

function collectDrivers(steps: StepDiffSummary[]): RootCauseDriver[] {
  const drivers: RootCauseDriver[] = []
  for (const s of steps) {
    for (const d of s.fieldDiffs) {
      if (!RESULT_COST_FIELDS.has(d.field) || d.deltaAbsolute === null) continue
      drivers.push({
        stepLabel: s.stepLabel,
        field: d.field,
        deltaAbsolute: d.deltaAbsolute,
        deltaPercent: d.deltaPercent,
      })
    }
  }
  return drivers
}

function totalFkDelta(steps: StepDiffSummary[]): number {
  let sum = 0
  for (const s of steps) {
    for (const d of s.fieldDiffs) {
      if (d.field === 'fk' && d.deltaAbsolute !== null) sum += d.deltaAbsolute
    }
  }
  return Number(sum.toFixed(2))
}

export function computeRootCause(input: RootCauseInput): RootCauseResult {
  const drivers = collectDrivers(input.steps)

  const topAbsoluteDrivers = [...drivers]
    .sort((a, b) => Math.abs(b.deltaAbsolute) - Math.abs(a.deltaAbsolute) || a.stepLabel.localeCompare(b.stepLabel))
    .slice(0, TOP_N)

  const topRelativeDrivers = drivers
    .filter((d) => d.deltaPercent !== null)
    .sort((a, b) => Math.abs(b.deltaPercent!) - Math.abs(a.deltaPercent!) || a.stepLabel.localeCompare(b.stepLabel))
    .slice(0, TOP_N)

  const structureChanges = {
    new: input.newSteps,
    removed: input.removedSteps,
    possible: input.structureChangeSteps,
  }

  const requiresReviewNote = input.structureChangeSteps.length > 0

  // ── Management summary — only from computed numbers ───────────────────────────
  const pn = input.partNumber ?? 'unbekannt'
  const sentences: string[] = []

  if (drivers.length === 0) {
    sentences.push(`Sachnummer ${pn}: keine vergleichbaren Prozessschritt-Deltas berechenbar.`)
  } else {
    const total = totalFkDelta(input.steps)
    const dir = total > 0 ? 'gestiegen' : total < 0 ? 'gesunken' : 'unverändert'
    sentences.push(`Sachnummer ${pn}: Fertigungskosten der Prozessschritte ${dir} (Summe FK-Delta ${fmt(total)}).`)

    if (topAbsoluteDrivers.length > 0) {
      const t = topAbsoluteDrivers[0]
      const sign = t.deltaAbsolute > 0 ? '+' : ''
      sentences.push(`Größter Treiber: ${t.stepLabel} (${String(t.field)} ${sign}${fmt(t.deltaAbsolute)}).`)
    }
  }

  const structParts: string[] = []
  if (structureChanges.new.length) structParts.push(`${structureChanges.new.length} neu`)
  if (structureChanges.removed.length) structParts.push(`${structureChanges.removed.length} entfallen`)
  if (structureChanges.possible.length) structParts.push(`${structureChanges.possible.length} mögliche Umstrukturierung`)
  if (structParts.length) sentences.push(`Strukturänderungen: ${structParts.join(', ')}.`)

  if (input.currencyChanged) {
    sentences.push('Achtung: Angebotswährung unterscheidet sich — Kostendeltas mit Wechselkurs-Vorbehalt bewerten.')
  }

  if (requiresReviewNote) {
    sentences.push('Unsicheres Matching vorhanden — bitte im Matching-Review bestätigen.')
  }

  return {
    partNumber: input.partNumber,
    topAbsoluteDrivers,
    topRelativeDrivers,
    structureChanges,
    currencyEffect: input.currencyChanged,
    managementSummary: sentences.join(' '),
    requiresReviewNote,
  }
}
