import { useState, useMemo, useEffect, useRef } from 'react'
import { RefreshCw, Sliders, Wifi, WifiOff } from 'lucide-react'
import clsx from 'clsx'

// ── Types ──────────────────────────────────────────────────────────────────────

interface Params {
  // FED / US
  fed_rate: number          // absolute, step 0.25
  fed_tone: number          // –3 hawkish … +3 dovish
  cpi_us_surprise: number   // ±0.5 %
  nfp_surprise: number      // ±300 k
  pmi_us: number            // 40–65
  // ECB / EU
  ecb_rate: number          // absolute, step 0.25
  ecb_tone: number          // –3 hawkish … +3 dovish
  cpi_eu_surprise: number   // ±0.5 %
  pmi_eu: number            // 40–65
  // Markets
  vix: number               // 10–60
  oil: number               // 40–130
  real_yield_us: number     // –1 … 4 %
  // Base anchors (set from live data, not displayed as sliders)
  us_2y: number
  us_10y: number
  eu_2y: number
  eu_10y: number
  eurusd: number
}

interface ModelResult {
  fed_rate_pressure: number   // rate channel signal (→ 2Y primarily)
  fed_fwd_signal: number      // tone/data channel signal (→ 10Y primarily)
  ecb_rate_pressure: number
  ecb_fwd_signal: number
  us_2y_implied: number
  us_10y_implied: number
  eu_2y_implied: number
  eu_10y_implied: number
  rate_diff_2y: number
  rate_diff_10y: number
  eurusd: number
  delta_pips: number
  contribs: { label: string; pips: number; color: 'red' | 'green' | 'slate' }[]
}

// ── Hardcoded fallback ─────────────────────────────────────────────────────────

const FALLBACK: Params = {
  fed_rate: 4.25,  ecb_rate: 3.65,
  fed_tone: 0,     ecb_tone: 0,
  cpi_us_surprise: 0,  cpi_eu_surprise: 0,
  nfp_surprise: 0,
  pmi_us: 50,      pmi_eu: 50,
  vix: 18,         oil: 80,  real_yield_us: 2.1,
  us_2y: 4.50,     us_10y: 4.30,
  eu_2y: 2.80,     eu_10y: 2.60,
  eurusd: 1.1450,
}

// ── Causal model ───────────────────────────────────────────────────────────────
//
// Two distinct transmission channels:
//   1. Rate channel (fait accompli → anchors short end):
//      fed_rate change → US 2Y (coefficient ~0.085)
//   2. Expectation/tone channel (forward guidance → long end):
//      fed_tone + CPI/NFP surprises → US 10Y (coefficient ~0.070)
//      with residual bleed into 2Y (~0.030) and 10Y from rate (~0.035)
//
// EUR/USD pip contributions:
//   Δ 2Y differential  → −500 pips / 1% spread widening
//   Δ 10Y differential → −200 pips / 1% spread widening
//   PMI diff, VIX, real yield, oil as secondary channels

function compute(p: Params, base: Params): ModelResult {
  // ── Rate pressure (current policy rate, already priced → hits 2Y hard) ─────
  const fed_rate_pressure = (p.fed_rate - base.fed_rate) / 0.25   // units of 25bps
  const ecb_rate_pressure = (p.ecb_rate - base.ecb_rate) / 0.25

  // ── Forward guidance / expectations (tone + data → shapes future path) ──────
  // Positive = hawkish signal for USD (tone: +3 dovish → signal = −3*1.2 → negative → dovish)
  const fed_fwd_signal =
    -p.fed_tone * 1.2
    + p.cpi_us_surprise / 0.1 * 0.50   // hot CPI → more hikes expected
    + p.nfp_surprise / 100 * 0.35       // strong jobs → Fed stays restrictive
    + (p.pmi_us - 50) / 5 * 0.18       // strong activity → Fed stays restrictive longer

  const ecb_fwd_signal =
    -p.ecb_tone * 1.2
    + p.cpi_eu_surprise / 0.1 * 0.45
    + (p.pmi_eu - 50) / 5 * 0.22

  // ── Implied yields ─────────────────────────────────────────────────────────
  // 2Y: 90% anchored by current rate, 10% by near-term guidance
  const us_2y_delta  = fed_rate_pressure * 0.085 + fed_fwd_signal * 0.030
  const eu_2y_delta  = ecb_rate_pressure * 0.080 + ecb_fwd_signal * 0.025

  // 10Y: 35% by current rate (level shift), 65% by long-term expectations
  const us_10y_delta = fed_rate_pressure * 0.035 + fed_fwd_signal * 0.070 + (p.pmi_us - 50) / 50 * 0.012
  const eu_10y_delta = ecb_rate_pressure * 0.030 + ecb_fwd_signal * 0.060 + (p.pmi_eu - 50) / 50 * 0.012

  const us_2y_implied  = base.us_2y  + us_2y_delta
  const us_10y_implied = base.us_10y + us_10y_delta
  const eu_2y_implied  = base.eu_2y  + eu_2y_delta
  const eu_10y_implied = base.eu_10y + eu_10y_delta

  const rate_diff_2y  = us_2y_implied  - eu_2y_implied
  const rate_diff_10y = us_10y_implied - eu_10y_implied

  const delta_diff_2y  = rate_diff_2y  - (base.us_2y  - base.eu_2y)
  const delta_diff_10y = rate_diff_10y - (base.us_10y - base.eu_10y)

  // ── Secondary channels ─────────────────────────────────────────────────────
  const pmi_diff = (p.pmi_eu - 50) - (p.pmi_us - 50)
  const vix_dev  = p.vix - base.vix
  const ry_dev   = p.real_yield_us - base.real_yield_us
  const oil_dev  = p.oil - base.oil

  // ── Pip contributions ──────────────────────────────────────────────────────
  const c_2y   = Math.round(-delta_diff_2y  * 500)   // rate channel (dominant)
  const c_10y  = Math.round(-delta_diff_10y * 200)   // tone/expectations channel
  const c_pmi  = Math.round(pmi_diff * 7)
  const c_vix  = Math.round(-vix_dev * 4)
  const c_ry   = Math.round(-ry_dev * 100)
  const c_oil  = Math.round(oil_dev * 0.5)

  const total_pips = c_2y + c_10y + c_pmi + c_vix + c_ry + c_oil

  const contribs = ([
    { label: 'Δ 2Y — taux directeurs',    pips: c_2y,  color: c_2y  < 0 ? 'red' : c_2y  > 0 ? 'green' : 'slate' },
    { label: 'Δ 10Y — anticipations/ton', pips: c_10y, color: c_10y < 0 ? 'red' : c_10y > 0 ? 'green' : 'slate' },
    { label: 'PMI diff (EU−US)',           pips: c_pmi, color: c_pmi > 0 ? 'green' : c_pmi < 0 ? 'red' : 'slate' },
    { label: 'VIX / Risk-off',            pips: c_vix, color: c_vix < 0 ? 'red'   : c_vix > 0 ? 'green' : 'slate' },
    { label: 'Taux réel US',              pips: c_ry,  color: c_ry  < 0 ? 'red'   : c_ry  > 0 ? 'green' : 'slate' },
    { label: 'Pétrole',                   pips: c_oil, color: c_oil > 0 ? 'green' : c_oil < 0 ? 'red'   : 'slate' },
  ] as ModelResult['contribs']).sort((a, b) => Math.abs(b.pips) - Math.abs(a.pips))

  return {
    fed_rate_pressure, fed_fwd_signal,
    ecb_rate_pressure, ecb_fwd_signal,
    us_2y_implied, us_10y_implied,
    eu_2y_implied, eu_10y_implied,
    rate_diff_2y, rate_diff_10y,
    eurusd: base.eurusd + total_pips / 10000,
    delta_pips: total_pips,
    contribs,
  }
}

// ── Slider (with click-to-edit value) ─────────────────────────────────────────

function Slider({
  label, value, min, max, step, format, onChange,
  colorize = false, reverse = false, center,
}: {
  label: string; value: number; min: number; max: number; step: number
  format: (v: number) => string; onChange: (v: number) => void
  colorize?: boolean; reverse?: boolean; center?: number
}) {
  const [editing, setEditing] = useState(false)
  const [draft, setDraft] = useState('')

  const pct   = ((value - min) / (max - min)) * 100
  const pivot = center ?? 0
  const mid   = Math.max(0, Math.min(100, ((pivot - min) / (max - min)) * 100))
  const atBase = Math.abs(value - pivot) < step / 2

  let trackColor = 'bg-blue-500'
  if (colorize) {
    const pos = reverse ? value < pivot : value > pivot
    trackColor = atBase ? 'bg-slate-600' : pos ? 'bg-emerald-500' : 'bg-rose-500'
  }

  const startEdit = () => { setDraft(String(value)); setEditing(true) }

  const commitEdit = () => {
    const v = parseFloat(draft.replace(',', '.'))
    if (!isNaN(v)) {
      const clamped = Math.max(min, Math.min(max, v))
      const snapped = Math.round((clamped - min) / step) * step + min
      onChange(parseFloat(snapped.toFixed(10)))
    }
    setEditing(false)
  }

  const isColored = colorize && !atBase
  const valueColor = isColored
    ? (reverse ? value < pivot : value > pivot) ? 'text-emerald-400' : 'text-rose-400'
    : 'text-white'

  return (
    <div className="space-y-1">
      <div className="flex items-center justify-between gap-2">
        <span className="text-xs text-slate-400 flex-1 min-w-0 truncate">{label}</span>
        {editing ? (
          <input
            autoFocus
            type="number"
            min={min} max={max} step={step}
            value={draft}
            onChange={e => setDraft(e.target.value)}
            onBlur={commitEdit}
            onKeyDown={e => {
              if (e.key === 'Enter') commitEdit()
              if (e.key === 'Escape') setEditing(false)
            }}
            className="w-20 bg-dark-900 border border-blue-500 rounded px-2 py-0.5 text-xs font-mono text-white text-right outline-none [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
          />
        ) : (
          <button
            onClick={startEdit}
            title="Cliquer pour saisir une valeur"
            className={clsx(
              'text-xs font-mono font-semibold shrink-0 px-1 py-0.5 rounded hover:bg-slate-700/40 cursor-text transition-colors',
              valueColor,
            )}
          >
            {format(value)}
          </button>
        )}
      </div>
      <div className="relative h-1.5 bg-dark-900 rounded overflow-hidden">
        <div className={clsx('absolute h-full rounded transition-all', trackColor)}
          style={colorize
            ? { left: `${Math.min(pct, mid)}%`, width: `${Math.abs(pct - mid)}%` }
            : { left: 0, width: `${pct}%` }} />
        {colorize && (
          <div className="absolute top-0 bottom-0 w-0.5 bg-slate-400 transition-all"
            style={{ left: `${Math.min(98.5, pct)}%` }} />
        )}
        <input type="range" min={min} max={max} step={step} value={value}
          onChange={e => onChange(parseFloat(e.target.value))}
          className="absolute inset-0 w-full opacity-0 cursor-pointer h-full" />
      </div>
    </div>
  )
}

// ── Tone selector ─────────────────────────────────────────────────────────────

const TONES = [
  { v: -3,   label: 'Très\nhawkish', color: 'border-rose-600/60 bg-rose-900/30 text-rose-300' },
  { v: -1.5, label: 'Hawkish',       color: 'border-rose-700/40 bg-rose-900/10 text-rose-400' },
  { v: 0,    label: 'Neutre',        color: 'border-slate-600/40 bg-dark-800 text-slate-300' },
  { v: 1.5,  label: 'Dovish',        color: 'border-emerald-700/40 bg-emerald-900/10 text-emerald-400' },
  { v: 3,    label: 'Très\ndovish',  color: 'border-emerald-600/60 bg-emerald-900/30 text-emerald-300' },
]

function ToneSelector({ label, value, onChange }: { label: string; value: number; onChange: (v: number) => void }) {
  return (
    <div className="space-y-1">
      <span className="text-xs text-slate-400">{label}</span>
      <div className="flex gap-1">
        {TONES.map(o => (
          <button key={o.v} onClick={() => onChange(o.v)}
            className={clsx('flex-1 px-1 py-1 rounded border text-[10px] leading-tight text-center transition-colors whitespace-pre-line',
              value === o.v ? o.color : 'border-slate-700/30 text-slate-600 bg-dark-900 hover:border-slate-600',
            )}>
            {o.label}
          </button>
        ))}
      </div>
    </div>
  )
}

// ── Causal chain SVG ──────────────────────────────────────────────────────────
// Two-channel layout:
//   Solid arrows  = rate channel (taux directeurs → 2Y)
//   Dashed arrows = tone/expectations channel (ton + données → 10Y)

function CausalChain({ r, base, p }: { r: ModelResult; base: Params; p: Params }) {
  const sign = (v: number) => v > 0 ? '+' : ''

  const delta2yVal  = r.rate_diff_2y  - (base.us_2y  - base.eu_2y)
  const delta10yVal = r.rate_diff_10y - (base.us_10y - base.eu_10y)

  const col3 = (v: number, threshold = 0.03): string =>
    Math.abs(v) < threshold ? '#94a3b8' : v > 0 ? '#f87171' : '#34d399'

  // ── Node colors ────────────────────────────────────────────────────────────
  // CPI/NFP/PMI inputs → forward guidance signal (positive = hawkish Fed = red for EUR)
  // Threshold 0.08 so PMI alone (~0.09-0.15 at typical deviations) triggers color
  const fedFwdC  = col3(r.fed_fwd_signal,    0.08)
  const ecbFwdC  = col3(-r.ecb_fwd_signal,   0.08)   // ECB hawkish fwd signal → green for EUR

  // CB nodes: combined rate + tone signal dominates
  const fedC = col3(r.fed_rate_pressure + r.fed_fwd_signal * 0.4, 0.25)
  const ecbC = col3(-(r.ecb_rate_pressure + r.ecb_fwd_signal * 0.4), 0.25)

  // PMI US: positive deviation (> 50) = US strong = bearish EUR = red
  const pmiUsC = col3(p.pmi_us - 50, 1.5)

  // VIX: above baseline = risk-off = USD safe haven = bearish EUR = red
  const vixC = col3(p.vix - base.vix, 2)

  // Yield node colors
  const us2C  = col3(r.us_2y_implied  - base.us_2y)
  const us10C = col3(r.us_10y_implied - base.us_10y)
  const eu2C  = col3(-(r.eu_2y_implied  - base.eu_2y))
  const eu10C = col3(-(r.eu_10y_implied - base.eu_10y))

  const diff2C  = col3(delta2yVal,  0.02)
  const diff10C = col3(delta10yVal, 0.02)
  const fxC     = r.delta_pips < -5 ? '#f87171' : r.delta_pips > 5 ? '#34d399' : '#94a3b8'

  const aw = (v: number) => Math.max(1, Math.min(3.5, Math.abs(v) * 1.2 + 1))

  const W = 400, H = 490
  const fedX = 100, ecbX = 300
  const us2X = 52, us10X = 155
  const eu2X = 348, eu10X = 245
  const diff2X = 140, diff10X = 260
  const vixX = 28
  const cX = 200

  const yIn1 = 38, yIn2 = 74
  const yCB  = 132
  const yYld = 220
  const yDiff = 310
  const yFX  = 400

  const COLORS = ['#f87171', '#34d399', '#94a3b8']
  const mk = (id: string, c: string) => (
    <marker key={id} id={id} viewBox="0 0 6 6" refX={5} refY={3} markerWidth={4} markerHeight={4} orient="auto">
      <path d="M0,0 L6,3 L0,6 Z" fill={c} />
    </marker>
  )

  const Node = ({ x, y, label, sub, col, w = 88 }: { x: number; y: number; label: string; sub?: string; col: string; w?: number }) => (
    <g>
      <rect x={x - w / 2} y={y - 16} width={w} height={sub ? 32 : 26} rx={5} fill="#1e293b" stroke={col} strokeWidth={1.5} />
      <text x={x} y={y - 2}  textAnchor="middle" fill={col} fontSize={9.5} fontWeight={600}>{label}</text>
      {sub && <text x={x} y={y + 11} textAnchor="middle" fill={col} fontSize={8.5} opacity={0.75}>{sub}</text>}
    </g>
  )

  const Arr = ({ x1, y1, x2, y2, col, w, dashed = false }: { x1: number; y1: number; x2: number; y2: number; col: string; w: number; dashed?: boolean }) => (
    <line x1={x1} y1={y1} x2={x2} y2={y2} stroke={col} strokeWidth={w} opacity={0.65}
      strokeDasharray={dashed ? '5 3' : undefined}
      markerEnd={`url(#a${col.replace('#', '')})`} />
  )

  return (
    <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} className="w-full">
      <defs>{COLORS.map(c => mk(`a${c.replace('#', '')}`, c))}</defs>

      {/* US inputs */}
      <Node x={fedX - 22} y={yIn1} label="CPI US / NFP" col={fedFwdC} w={98} />
      <Node x={fedX + 30} y={yIn2} label="PMI US"        col={pmiUsC} w={70} />
      <Arr x1={fedX - 8} y1={yIn1 + 14} x2={fedX - 5}  y2={yCB - 17} col={fedFwdC} w={1.4} dashed />
      <Arr x1={fedX + 28} y1={yIn2 + 13} x2={fedX + 8} y2={yCB - 17} col={pmiUsC}  w={1.1} dashed />

      {/* EU inputs */}
      <Node x={ecbX + 22} y={yIn1} label="CPI EU / PMI" col={ecbFwdC} w={98} />
      <Arr x1={ecbX + 8} y1={yIn1 + 14} x2={ecbX + 5}  y2={yCB - 17} col={ecbFwdC} w={1.4} dashed />

      {/* CB nodes */}
      <Node x={fedX} y={yCB} label="FED"
        sub={`taux ${sign(r.fed_rate_pressure)}${r.fed_rate_pressure.toFixed(1)} | ton ${sign(r.fed_fwd_signal)}${r.fed_fwd_signal.toFixed(1)}`}
        col={fedC} w={118} />
      <Node x={ecbX} y={yCB} label="BCE"
        sub={`taux ${sign(r.ecb_rate_pressure)}${r.ecb_rate_pressure.toFixed(1)} | ton ${sign(r.ecb_fwd_signal)}${r.ecb_fwd_signal.toFixed(1)}`}
        col={ecbC} w={118} />

      {/* FED → US 2Y (solid, rate) and FED → US 10Y (dashed, tone) */}
      <Arr x1={fedX - 18} y1={yCB + 17} x2={us2X + 8}  y2={yYld - 17} col={us2C}  w={aw(Math.abs(r.fed_rate_pressure) * 0.085)} />
      <Arr x1={fedX + 18} y1={yCB + 17} x2={us10X - 8} y2={yYld - 17} col={us10C} w={aw(Math.abs(r.fed_fwd_signal) * 0.07)} dashed />

      {/* BCE → EU 2Y (solid) and BCE → EU 10Y (dashed) */}
      <Arr x1={ecbX + 18} y1={yCB + 17} x2={eu2X - 8}  y2={yYld - 17} col={eu2C}  w={aw(Math.abs(r.ecb_rate_pressure) * 0.080)} />
      <Arr x1={ecbX - 18} y1={yCB + 17} x2={eu10X + 8} y2={yYld - 17} col={eu10C} w={aw(Math.abs(r.ecb_fwd_signal) * 0.060)} dashed />

      {/* Yield nodes */}
      <Node x={us2X}  y={yYld} label="US 2Y"    sub={`${r.us_2y_implied.toFixed(2)}%`}  col={us2C}  w={76} />
      <Node x={us10X} y={yYld} label="US 10Y"   sub={`${r.us_10y_implied.toFixed(2)}%`} col={us10C} w={76} />
      <Node x={eu2X}  y={yYld} label="Bund 2Y"  sub={`${r.eu_2y_implied.toFixed(2)}%`}  col={eu2C}  w={76} />
      <Node x={eu10X} y={yYld} label="Bund 10Y" sub={`${r.eu_10y_implied.toFixed(2)}%`} col={eu10C} w={76} />

      {/* Yields → differentials */}
      <Arr x1={us2X  + 20} y1={yYld + 16} x2={diff2X  - 8}  y2={yDiff - 17} col={us2C}  w={aw(Math.abs(r.us_2y_implied  - base.us_2y))} />
      <Arr x1={eu2X  - 20} y1={yYld + 16} x2={diff2X  + 8}  y2={yDiff - 17} col={eu2C}  w={aw(Math.abs(r.eu_2y_implied  - base.eu_2y))} />
      <Arr x1={us10X + 14} y1={yYld + 16} x2={diff10X - 8}  y2={yDiff - 17} col={us10C} w={aw(Math.abs(r.us_10y_implied - base.us_10y))} dashed />
      <Arr x1={eu10X - 14} y1={yYld + 16} x2={diff10X + 8}  y2={yDiff - 17} col={eu10C} w={aw(Math.abs(r.eu_10y_implied - base.eu_10y))} dashed />

      {/* Differential nodes */}
      <Node x={diff2X}  y={yDiff} label="Δ 2Y (taux)"    sub={`${r.rate_diff_2y.toFixed(2)}% US−EU`}  col={diff2C}  w={108} />
      <Node x={diff10X} y={yDiff} label="Δ 10Y (anticipations)" sub={`${r.rate_diff_10y.toFixed(2)}% US−EU`} col={diff10C} w={114} />

      {/* VIX (left) — risk-off = USD safe haven = bearish EUR = red */}
      <Node x={vixX} y={yDiff} label="VIX" sub={`${p.vix.toFixed(1)}`} col={vixC} w={52} />
      <Arr x1={vixX + 26} y1={yDiff + 8} x2={cX - 68} y2={yFX - 16} col={vixC} w={aw(Math.abs(p.vix - base.vix) * 0.06)} />

      {/* Differentials → EURUSD */}
      <Arr x1={diff2X  + 12} y1={yDiff + 17} x2={cX - 22} y2={yFX - 22} col={diff2C}  w={aw(Math.abs(delta2yVal)  * 5)} />
      <Arr x1={diff10X - 12} y1={yDiff + 17} x2={cX + 22} y2={yFX - 22} col={diff10C} w={aw(Math.abs(delta10yVal) * 2)} dashed />

      {/* EURUSD box */}
      <rect x={cX - 78} y={yFX - 22} width={156} height={44} rx={8} fill="#1e3a5f" stroke={fxC} strokeWidth={2} />
      <text x={cX} y={yFX - 5}  textAnchor="middle" fill={fxC} fontSize={11} fontWeight={700}>EURUSD</text>
      <text x={cX} y={yFX + 13} textAnchor="middle" fill={fxC} fontSize={13} fontWeight={800}>{r.eurusd.toFixed(4)}</text>

      {/* Legend */}
      <line x1={cX - 64} y1={H - 14} x2={cX - 46} y2={H - 14} stroke="#64748b" strokeWidth={1.5} opacity={0.7} />
      <text x={cX - 41} y={H - 10} fill="#64748b" fontSize={8} opacity={0.7}>taux (2Y)</text>
      <line x1={cX + 18} y1={H - 14} x2={cX + 36} y2={H - 14} stroke="#64748b" strokeWidth={1.5} strokeDasharray="5 3" opacity={0.7} />
      <text x={cX + 40} y={H - 10} fill="#64748b" fontSize={8} opacity={0.7}>ton (10Y)</text>
    </svg>
  )
}

// ── Sensitivity bar ────────────────────────────────────────────────────────────

function SensBar({ label, pips, maxAbs }: { label: string; pips: number; maxAbs: number }) {
  const pct = maxAbs > 0 ? (Math.abs(pips) / maxAbs) * 100 : 0
  return (
    <div className="grid grid-cols-[140px_1fr_48px] items-center gap-2">
      <span className="text-xs text-slate-400 truncate">{label}</span>
      <div className="h-2 bg-dark-900 rounded overflow-hidden">
        <div className={clsx('h-full rounded transition-all', pips > 0 ? 'bg-emerald-500' : 'bg-rose-500')}
          style={{ width: `${pct}%` }} />
      </div>
      <span className={clsx('text-xs font-mono text-right', pips > 0 ? 'text-emerald-400' : 'text-rose-400')}>
        {pips > 0 ? '+' : ''}{pips}p
      </span>
    </div>
  )
}

function Section({ title, children, color }: { title: string; children: React.ReactNode; color: string }) {
  return (
    <div className={clsx('rounded-lg border p-3 space-y-3', color)}>
      <div className="text-xs font-semibold uppercase tracking-wider text-slate-300">{title}</div>
      {children}
    </div>
  )
}

// ── Main page ─────────────────────────────────────────────────────────────────

interface Baseline {
  fed_rate: number; ecb_rate: number
  us_2y: number; us_10y: number
  eu_2y: number; eu_10y: number
  eurusd: number; vix: number; oil: number; real_yield_us: number
  fetched_at?: string; sources?: Record<string, string>
}

export default function EuroSimulator() {
  const [base, setBase]       = useState<Params>(FALLBACK)
  const [p, setP]             = useState<Params>(FALLBACK)
  const [liveStatus, setLive] = useState<'loading' | 'ok' | 'fallback'>('loading')
  const [fetchedAt, setAt]    = useState<string | null>(null)
  const [sources, setSources] = useState<Record<string, string>>({})
  const fetched               = useRef(false)

  const set = (k: keyof Params, v: number) => setP(prev => ({ ...prev, [k]: v }))

  useEffect(() => {
    if (fetched.current) return
    fetched.current = true
    fetch('/api/simulator/baseline')
      .then(r => r.json())
      .then((data: Baseline) => {
        const newBase: Params = {
          ...FALLBACK,
          fed_rate:      data.fed_rate      ?? FALLBACK.fed_rate,
          ecb_rate:      data.ecb_rate      ?? FALLBACK.ecb_rate,
          us_2y:         data.us_2y         ?? FALLBACK.us_2y,
          us_10y:        data.us_10y        ?? FALLBACK.us_10y,
          eu_2y:         data.eu_2y         ?? FALLBACK.eu_2y,
          eu_10y:        data.eu_10y        ?? FALLBACK.eu_10y,
          eurusd:        data.eurusd        ?? FALLBACK.eurusd,
          vix:           data.vix           ?? FALLBACK.vix,
          oil:           data.oil           ?? FALLBACK.oil,
          real_yield_us: data.real_yield_us ?? FALLBACK.real_yield_us,
        }
        setBase(newBase)
        setP(newBase)
        setLive('ok')
        setAt(data.fetched_at ?? null)
        setSources(data.sources ?? {})
      })
      .catch(() => setLive('fallback'))
  }, [])

  const r = useMemo(() => compute(p, base), [p, base])

  const maxAbs      = useMemo(() => Math.max(1, ...r.contribs.map(c => Math.abs(c.pips))), [r.contribs])
  const eurusdColor = r.delta_pips < -5 ? 'text-rose-400' : r.delta_pips > 5 ? 'text-emerald-400' : 'text-slate-300'

  return (
    <div className="p-4 max-w-[1400px] mx-auto space-y-4">

      {/* Header */}
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-3">
          <Sliders className="w-5 h-5 text-blue-400" />
          <div>
            <h1 className="text-lg font-bold text-white">Simulateur EUR/USD</h1>
            <p className="text-xs text-slate-500">Modèle causal 2 canaux — taux directeurs → 2Y · ton/données → 10Y</p>
          </div>
        </div>

        <div className="flex items-center gap-3">
          <div className={clsx('flex items-center gap-1.5 px-2.5 py-1 rounded border text-xs',
            liveStatus === 'loading' ? 'border-slate-700/40 text-slate-500' :
            liveStatus === 'ok'      ? 'border-emerald-700/40 bg-emerald-900/20 text-emerald-400' :
                                       'border-amber-700/40 bg-amber-900/20 text-amber-400',
          )}>
            {liveStatus === 'ok' ? <Wifi className="w-3 h-3" /> : <WifiOff className="w-3 h-3" />}
            {liveStatus === 'loading' ? 'Chargement…' :
             liveStatus === 'ok'      ? `Live — base ${fetchedAt ? fetchedAt.slice(0, 10) : ''}` :
                                        'Fallback — données hardcodées'}
          </div>

          <button onClick={() => setP(base)}
            className="flex items-center gap-1.5 px-3 py-1.5 rounded border border-slate-700/40 text-xs text-slate-400 hover:text-white hover:border-slate-500 transition-colors">
            <RefreshCw className="w-3.5 h-3.5" />
            Reset
          </button>
        </div>
      </div>

      <div className="grid grid-cols-[320px_1fr_280px] gap-4 items-start">

        {/* ── Controls ──────────────────────────────────────────────────────── */}
        <div className="space-y-3">

          <Section title="🇺🇸 Politique monétaire US (FED)" color="border-rose-900/30 bg-rose-950/10">
            <Slider label="Taux directeur FED" value={p.fed_rate} min={0} max={6} step={0.25}
              format={v => `${v.toFixed(2)}%`} onChange={v => set('fed_rate', v)} />
            <ToneSelector label="Ton FED" value={p.fed_tone} onChange={v => set('fed_tone', v)} />
            <Slider label="Surprise CPI US" value={p.cpi_us_surprise} min={-0.5} max={0.5} step={0.05}
              format={v => `${v > 0 ? '+' : ''}${v.toFixed(2)}%`}
              onChange={v => set('cpi_us_surprise', v)} colorize reverse />
            <Slider label="Surprise NFP" value={p.nfp_surprise} min={-300} max={300} step={10}
              format={v => `${v > 0 ? '+' : ''}${v}k`}
              onChange={v => set('nfp_surprise', v)} colorize reverse />
            <Slider label="PMI manufacturier US" value={p.pmi_us} min={40} max={65} step={0.5}
              format={v => v.toFixed(1)} onChange={v => set('pmi_us', v)} />
          </Section>

          <Section title="🇪🇺 Politique monétaire EU (BCE)" color="border-emerald-900/30 bg-emerald-950/10">
            <Slider label="Taux directeur BCE" value={p.ecb_rate} min={0} max={5} step={0.25}
              format={v => `${v.toFixed(2)}%`} onChange={v => set('ecb_rate', v)} />
            <ToneSelector label="Ton BCE" value={p.ecb_tone} onChange={v => set('ecb_tone', v)} />
            <Slider label="Surprise CPI EU" value={p.cpi_eu_surprise} min={-0.5} max={0.5} step={0.05}
              format={v => `${v > 0 ? '+' : ''}${v.toFixed(2)}%`}
              onChange={v => set('cpi_eu_surprise', v)} colorize />
            <Slider label="PMI manufacturier EU" value={p.pmi_eu} min={40} max={65} step={0.5}
              format={v => v.toFixed(1)} onChange={v => set('pmi_eu', v)} />
          </Section>

          <Section title="📊 Marchés & sentiment" color="border-slate-700/30 bg-dark-800/60">
            <Slider label="VIX" value={p.vix} min={10} max={60} step={0.5}
              format={v => v.toFixed(1)} onChange={v => set('vix', v)}
              colorize reverse center={base.vix} />
            <Slider label="Pétrole (USD/bbl)" value={p.oil} min={40} max={130} step={1}
              format={v => `$${v.toFixed(0)}`} onChange={v => set('oil', v)} />
            <Slider label="Taux réel US 10Y" value={p.real_yield_us} min={-1} max={4} step={0.05}
              format={v => `${v > 0 ? '+' : ''}${v.toFixed(2)}%`}
              onChange={v => set('real_yield_us', v)} colorize reverse center={base.real_yield_us} />
          </Section>

          {/* Sources panel */}
          {liveStatus === 'ok' && Object.keys(sources).length > 0 && (
            <div className="rounded-lg border border-slate-800/60 bg-dark-900/60 p-3 space-y-1">
              <div className="text-[10px] text-slate-600 uppercase tracking-wider mb-1">Sources baseline</div>
              {Object.entries(sources).map(([k, v]) => (
                <div key={k} className="flex justify-between text-[10px]">
                  <span className="text-slate-600">{k}</span>
                  <span className="text-slate-500 font-mono">{v}</span>
                </div>
              ))}
            </div>
          )}
        </div>

        {/* ── Causal chain ──────────────────────────────────────────────────── */}
        <div className="bg-dark-800/60 rounded-xl border border-slate-700/30 p-4 flex flex-col items-center">
          <div className="text-xs text-slate-500 mb-3 uppercase tracking-wider">Chaîne de transmission causale</div>

          {/* Metric strip — 6 cells in 3×2 grid */}
          <div className="w-full grid grid-cols-3 gap-2 mb-4">
            {(() => {
              const d2  = r.us_2y_implied  - base.us_2y
              const d10 = r.us_10y_implied - base.us_10y
              const ed2  = r.eu_2y_implied  - base.eu_2y
              const ed10 = r.eu_10y_implied - base.eu_10y
              const baseDiff2  = base.us_2y  - base.eu_2y
              const baseDiff10 = base.us_10y - base.eu_10y
              return [
                { label: 'US 2Y',    val: `${r.us_2y_implied.toFixed(2)}%`,  col: Math.abs(d2)  < 0.01 ? 'text-slate-400' : d2  > 0 ? 'text-rose-400'    : 'text-emerald-400' },
                { label: 'US 10Y',   val: `${r.us_10y_implied.toFixed(2)}%`, col: Math.abs(d10) < 0.01 ? 'text-slate-400' : d10 > 0 ? 'text-rose-400'    : 'text-emerald-400' },
                { label: 'Bund 2Y',  val: `${r.eu_2y_implied.toFixed(2)}%`,  col: Math.abs(ed2)  < 0.01 ? 'text-slate-400' : ed2  > 0 ? 'text-emerald-400' : 'text-rose-400' },
                { label: 'Bund 10Y', val: `${r.eu_10y_implied.toFixed(2)}%`, col: Math.abs(ed10) < 0.01 ? 'text-slate-400' : ed10 > 0 ? 'text-emerald-400' : 'text-rose-400' },
                { label: 'Δ 2Y',     val: `${r.rate_diff_2y.toFixed(2)}%`,   col: r.rate_diff_2y  > baseDiff2  + 0.01 ? 'text-rose-400' : r.rate_diff_2y  < baseDiff2  - 0.01 ? 'text-emerald-400' : 'text-slate-400' },
                { label: 'Δ 10Y',    val: `${r.rate_diff_10y.toFixed(2)}%`,  col: r.rate_diff_10y > baseDiff10 + 0.01 ? 'text-rose-400' : r.rate_diff_10y < baseDiff10 - 0.01 ? 'text-emerald-400' : 'text-slate-400' },
              ]
            })().map(it => (
              <div key={it.label} className="bg-dark-900 rounded-lg p-2 text-center">
                <div className="text-[10px] text-slate-600 uppercase tracking-wider">{it.label}</div>
                <div className={clsx('text-sm font-mono font-semibold mt-0.5', it.col)}>{it.val}</div>
              </div>
            ))}
          </div>

          <CausalChain r={r} base={base} p={p} />

          <div className="mt-2 text-[10px] text-slate-600 text-center">
            Base: EURUSD {base.eurusd.toFixed(4)} · US 2Y {base.us_2y.toFixed(2)}% · US 10Y {base.us_10y.toFixed(2)}% · Bund 10Y {base.eu_10y.toFixed(2)}%
          </div>
        </div>

        {/* ── Results ───────────────────────────────────────────────────────── */}
        <div className="space-y-3">

          {/* EUR/USD display */}
          <div className="bg-dark-800/60 rounded-xl border border-slate-700/30 p-4 text-center">
            <div className="text-xs text-slate-500 uppercase tracking-wider mb-1">EUR/USD simulé</div>
            <div className={clsx('text-4xl font-mono font-bold tracking-tight', eurusdColor)}>
              {r.eurusd.toFixed(4)}
            </div>
            <div className={clsx('text-base font-mono mt-1', eurusdColor)}>
              {r.delta_pips === 0 ? 'Neutre' : `${r.delta_pips > 0 ? '+' : ''}${r.delta_pips} pips`}
            </div>
            <div className="text-xs text-slate-600 mt-1">vs base {base.eurusd.toFixed(4)}</div>

            {/* 4 signal gauges: FED rate/tone + BCE rate/tone */}
            <div className="grid grid-cols-2 gap-2 mt-4">
              {[
                { label: 'FED — taux',  v: r.fed_rate_pressure, posL: 'Hawkish', negL: 'Dovish', posC: 'text-rose-400',    negC: 'text-emerald-400' },
                { label: 'FED — ton',   v: r.fed_fwd_signal,    posL: 'Hawkish', negL: 'Dovish', posC: 'text-rose-400',    negC: 'text-emerald-400' },
                { label: 'BCE — taux',  v: r.ecb_rate_pressure, posL: 'Hawkish', negL: 'Dovish', posC: 'text-emerald-400', negC: 'text-rose-400' },
                { label: 'BCE — ton',   v: r.ecb_fwd_signal,    posL: 'Hawkish', negL: 'Dovish', posC: 'text-emerald-400', negC: 'text-rose-400' },
              ].map(g => (
                <div key={g.label} className="bg-dark-900 rounded p-2">
                  <div className="text-[10px] text-slate-600">{g.label}</div>
                  <div className={clsx('text-xs font-semibold',
                    g.v > 0.2 ? g.posC : g.v < -0.2 ? g.negC : 'text-slate-400',
                  )}>
                    {g.v > 0.2 ? g.posL : g.v < -0.2 ? g.negL : 'Neutre'}
                  </div>
                  <div className="text-[10px] font-mono text-slate-500">{g.v > 0 ? '+' : ''}{g.v.toFixed(1)}</div>
                </div>
              ))}
            </div>
          </div>

          {/* Pip decomposition */}
          <div className="bg-dark-800/60 rounded-xl border border-slate-700/30 p-4 space-y-2">
            <div className="text-xs text-slate-500 uppercase tracking-wider mb-2">
              Décomposition ({r.delta_pips > 0 ? '+' : ''}{r.delta_pips} pips)
            </div>
            {r.contribs.map(c => <SensBar key={c.label} label={c.label} pips={c.pips} maxAbs={maxAbs} />)}
          </div>

          {/* Relative influence */}
          <div className="bg-dark-800/60 rounded-xl border border-slate-700/30 p-3 space-y-1.5">
            <div className="text-xs text-slate-500 uppercase tracking-wider mb-1">Influence relative</div>
            {r.contribs.slice(0, 5).map(c => (
              <div key={c.label} className="flex items-center gap-2 text-[11px]">
                <div className={clsx('w-2 h-2 rounded-full shrink-0', c.pips > 0 ? 'bg-emerald-500' : 'bg-rose-500')} />
                <span className="text-slate-400 flex-1 truncate">{c.label}</span>
                <span className="text-slate-500 font-mono">
                  {maxAbs > 0 ? Math.round((Math.abs(c.pips) / maxAbs) * 100) : 0}%
                </span>
              </div>
            ))}
          </div>

          <div className="bg-dark-900/80 rounded-lg border border-slate-800/60 p-3 text-[10px] text-slate-600 leading-relaxed space-y-1">
            <div><span className="text-slate-500 font-medium">Canal taux (solid) :</span> variations des taux directeurs → principalement US/Bund 2Y. Réponse rapide, déjà pricée.</div>
            <div><span className="text-slate-500 font-medium">Canal ton (tirets) :</span> discours des CBs + surprises CPI/NFP → principalement 10Y. Anticipe la trajectoire future des taux.</div>
            <div className="text-slate-700">Coefficients heuristiques — non calibrés sur données historiques.</div>
          </div>
        </div>
      </div>
    </div>
  )
}
