'use client'

import { useCallback, useEffect, useState } from 'react'
import { CRADemo, CRAFinding, Measure, DEMO_SCENARIO } from './useCRADemo'
import { fetchProjectSafetyFunctions, SafetyFunction } from './iace-safety-bridge'

// Live CRA assessment: POST the (demo) findings + customer weights + the project's
// safety functions to /api/v1/cra/assess and merge the live, priority-sorted
// mapping with the frontend scenario constants. Also save/list versioned
// snapshots (the CRA Art. 13 running system). Falls back to the static scenario
// if the backend is unreachable.

export type Weights = Record<string, string> // objective -> high|medium|low

export interface SnapshotMeta {
  id: string
  version: number
  status: string
  generated_at: string
  coverage?: { covered?: string[]; total?: number }
}

const SAFETY_FUNCTIONS = [
  {
    name: 'Zweihandschaltung + trennende Schutzeinrichtung am Hubwerk',
    hazard: 'Unerwarteter Anlauf des Hubwerks → Quetschen zwischen Last und Rahmen',
    original_measure: 'Zweihandschaltung + trennende Schutzeinrichtung (mechanisch, PL d)',
    kind: 'prevent_unexpected_actuation',
  },
  {
    name: 'Überlastsicherung / Lastmomentbegrenzer',
    hazard: 'Überlast / Lastabsturz durch manipulierte Lastgrenze',
    original_measure: 'Überlastsicherung / Lastmomentbegrenzer',
    kind: 'signal_integrity',
  },
]

function reqTitle(rationale: string): string {
  const i = rationale.indexOf(': ')
  return i >= 0 ? rationale.slice(i + 2) : rationale
}

function merge(live: any): CRADemo {
  const meta: Record<string, CRAFinding> = {}
  for (const f of DEMO_SCENARIO.findings) meta[f.id] = f

  const findings: CRAFinding[] = (live.mapped || []).map((m: any) => {
    const base = meta[m.finding_id]
    return {
      ...(base || { id: m.finding_id, title: m.finding_id, location: '', scanner_severity: '', cwe: '' }),
      primary_requirement: m.primary_requirement,
      requirement_title: reqTitle(m.rationale || ''),
      requirement_ids: m.requirement_ids || [],
      annex_anchor: m.annex_anchor || '',
      iso27001_ref: m.iso27001_ref || [],
      nist_refs: m.nist_refs || [],
      owasp_refs: m.owasp_refs || [],
      risk_level: m.risk_level || (base ? base.risk_level : 'LOW'),
      measures: m.measures || [],
      evidence_type: m.evidence_type,
      sub_topic: m.sub_topic,
      regulatory_breadth: m.regulatory_breadth || [],
      priority_tier: m.priority_tier,
      priority_score: m.priority_score,
      quick_win: m.quick_win,
      priority_reason: m.priority_reason,
      objective: m.objective,
    } as CRAFinding
  })

  const open_measures: Measure[] = (live.open_measures || []).map((om: any) => ({
    id: om.id,
    name: om.name || DEMO_SCENARIO.open_measures.find((d) => d.id === om.id)?.name || om.id,
    description: om.description || '',
    norm_refs: om.norm_refs || [],
    norm_sources: om.norm_sources || [],
    tier: om.tier,
    provenance: om.provenance,
  }))

  return {
    scenario: DEMO_SCENARIO.scenario,
    findings,
    by_risk: live.by_risk || DEMO_SCENARIO.by_risk,
    coverage_pct: live.coverage_pct ?? DEMO_SCENARIO.coverage_pct,
    requirements_touched: live.requirements_touched || DEMO_SCENARIO.requirements_touched,
    open_measures,
    cross_links: live.cross_links && live.cross_links.length ? live.cross_links : DEMO_SCENARIO.cross_links,
    deadlines: live.deadlines || DEMO_SCENARIO.deadlines,
    quick_wins: live.quick_wins || [],
    objectives: live.objectives || [],
  }
}

export function useCRA(projectId?: string) {
  const [data, setData] = useState<CRADemo | null>(null)
  const [live, setLive] = useState(false)
  const [scannerRepo, setScannerRepoState] = useState('')   // pull-flow: chosen scanner repo_id
  const [weights, setWeights] = useState<Weights>({})
  const [snapshots, setSnapshots] = useState<SnapshotMeta[]>([])
  // Cyber-meets-CE: real safety functions derived from THIS IACE project's
  // hazards/mitigations (falls back to the demo set until they load / if empty).
  const [safetyFunctions, setSafetyFunctions] = useState<SafetyFunction[]>(SAFETY_FUNCTIONS)

  useEffect(() => {
    if (!projectId) return
    let cancelled = false
    fetchProjectSafetyFunctions(projectId).then((sf) => {
      if (!cancelled && sf.length) setSafetyFunctions(sf)
    })
    return () => { cancelled = true }
  }, [projectId])

  const buildPayload = useCallback(() => ({
    findings: DEMO_SCENARIO.findings.map((f) => ({
      id: f.id, title: f.title, cwe: f.cwe, severity: f.scanner_severity, location: f.location,
    })),
    weights,
    safety_functions: safetyFunctions,
  }), [weights, safetyFunctions])

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      // 0. Pull-flow: a scanner repo is chosen → assess its real findings.
      if (scannerRepo) {
        try {
          const r = await fetch('/api/v1/cra/assess-from-scanner', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ repo_id: scannerRepo, weights, safety_functions: safetyFunctions }),
          })
          if (r.ok) {
            const j = await r.json()
            if (!cancelled) { setData(merge(j)); setLive(true) }
            return
          }
        } catch { /* fall through */ }
      }
      // 1. Is a CRA project LINKED to this IACE project? Then show its real
      //    assessment (latest snapshot) instead of the demo scenario.
      if (projectId) {
        try {
          const lr = await fetch(`/api/v1/cra/by-iace/${projectId}`)
          if (lr.ok) {
            const link = await lr.json()
            if (link?.linked && link.assessment) {
              if (!cancelled) { setData(merge(link.assessment)); setLive(true) }
              return
            }
          }
        } catch { /* fall through to the demo assess */ }
      }
      // 2. Fallback: live demo assess (scenario findings).
      try {
        const r = await fetch('/api/v1/cra/assess', {
          method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(buildPayload()),
        })
        if (!r.ok) throw new Error(`HTTP ${r.status}`)
        const j = await r.json()
        if (!cancelled) { setData(merge(j)); setLive(true) }
      } catch (err) {
        console.error('CRA assess fetch failed, using static scenario:', err)
        if (!cancelled) { setData(DEMO_SCENARIO); setLive(false) }
      }
    })()
    return () => { cancelled = true }
  }, [buildPayload, projectId, scannerRepo, weights, safetyFunctions])

  const refreshSnapshots = useCallback(() => {
    if (!projectId) return
    fetch(`/api/v1/cra/projects/${projectId}/assess-snapshots`)
      .then((r) => (r.ok ? r.json() : null))
      .then((j) => { if (j) setSnapshots(j.snapshots || []) })
      .catch(() => {})
  }, [projectId])

  useEffect(() => { refreshSnapshots() }, [refreshSnapshots])

  const saveSnapshot = useCallback(async () => {
    if (!projectId) return
    await fetch(`/api/v1/cra/projects/${projectId}/assess-snapshot`, {
      method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(buildPayload()),
    })
    refreshSnapshots()
  }, [projectId, buildPayload, refreshSnapshots])

  const viewSnapshot = useCallback(async (id: string) => {
    const r = await fetch(`/api/v1/cra/assess-snapshots/${id}`)
    return r.ok ? r.json() : null
  }, [])

  // Pull-flow mapping: load the persisted scanner repo for this IACE project,
  // and persist it on change (replaces the old ephemeral dropdown state).
  useEffect(() => {
    if (!projectId) return
    fetch(`/api/v1/cra/scanner-repo-map/${projectId}`)
      .then((r) => (r.ok ? r.json() : null))
      .then((j) => { if (j?.scanner_repo_id) setScannerRepoState(j.scanner_repo_id) })
      .catch(() => {})
  }, [projectId])

  const setScannerRepo = useCallback((v: string) => {
    setScannerRepoState(v)
    if (projectId) {
      fetch(`/api/v1/cra/scanner-repo-map/${projectId}`, {
        method: 'PUT', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ scanner_repo_id: v }),
      }).catch(() => {})
    }
  }, [projectId])

  return { data, live, weights, setWeights, snapshots, saveSnapshot, viewSnapshot, scannerRepo, setScannerRepo }
}
