import { useState, useEffect, useCallback } from 'react'
import clsx from 'clsx'
import { RefreshCw, TrendingUp, TrendingDown, Minus, Database } from 'lucide-react'
import {
  ComposedChart, Line, Bar, XAxis, YAxis, CartesianGrid, Tooltip,
  ResponsiveContainer, ReferenceLine, Area, Legend,
} from 'recharts'

const API = ''

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

interface SeriesMeta {
  id: string
  name: string
  category: string
  freq: string
  unit: string
  assets: string[]
}

interface TSPoint {
  event_date: string
  actual_value: number | null
  surprise_zscore: number | null
  surprise_direction: string | null
}

interface FFEvent {
  event_date: string
  event_time: string | null
  event_name: string
  actual_value: string | null
  forecast_value: string | null
  previous_value: string | null
  impact: string
}

interface SeriesHistory {
  series_id: string
  name: string
  unit: string
  category: string
  freq: string
  timeseries: TSPoint[]
  events: FFEvent[]
}

interface LogEntry {
  series_id: string
  event_name: string
  event_date: string
  actual_value: number | null
  forecast_value: number | null
  previous_value: number | null
  logged_at: string
  changed: string  // 'new' | 'actual' | 'forecast' | 'both' | 'backfill'
}

// ── Constants ─────────────────────────────────────────────────────────────────

const CATEGORY_COLORS: Record<string, string> = {
  employment: '#3b82f6',
  inflation:  '#f59e0b',
  growth:     '#10b981',
  monetary:   '#8b5cf6',
  credit:     '#ef4444',
  rates:      '#06b6d4',
}

const CATEGORY_LABELS: Record<string, string> = {
  employment: 'Employment',
  inflation:  'Inflation',
  growth:     'Growth',
  monetary:   'Monetary',
  credit:     'Credit',
  rates:      'Rates',
}

const RANGE_OPTIONS = [
  { key: '1y',  label: '1Y',  months: 12 },
  { key: '2y',  label: '2Y',  months: 24 },
  { key: '5y',  label: '5Y',  months: 60 },
  { key: '10y', label: '10Y', months: 120 },
  { key: 'all', label: 'All', months: 999 },
]

// ── Helpers ───────────────────────────────────────────────────────────────────

function fromDateForRange(months: number): string {
  if (months >= 999) return '2007-01-01'
  const d = new Date()
  d.setMonth(d.getMonth() - months)
  return d.toISOString().slice(0, 10)
}

function fmtDate(s: string): string {
  return s.slice(0, 7) // YYYY-MM
}

function fmtVal(v: number | null, unit: string): string {
  if (v === null) return '—'
  const fixed = Math.abs(v) < 10 ? 2 : 1
  return `${v.toFixed(fixed)} ${unit}`
}

// ── Custom Tooltip ────────────────────────────────────────────────────────────

interface TooltipPayload {
  event_date: string
  value: number | null
  zscore: number | null
  direction: string | null
  ff_actual?: string
  ff_forecast?: string
  ff_event?: string
}

function ChartTooltip({ active, payload, unit }: {
  active?: boolean
  payload?: Array<{ payload: TooltipPayload }>
  unit: string
}) {
  if (!active || !payload?.length) return null
  const d = payload[0].payload
  return (
    <div className="bg-slate-900 border border-slate-600 rounded p-2.5 text-xs shadow-xl min-w-[160px]">
      <div className="text-slate-400 mb-1">{d.event_date}</div>
      <div className="text-white font-semibold mb-1">
        {d.value !== null ? `${d.value?.toFixed(2)} ${unit}` : '—'}
      </div>
      {d.zscore !== null && (
        <div className={clsx(
          'text-xs',
          d.direction === 'bullish' ? 'text-emerald-400' :
          d.direction === 'bearish' ? 'text-red-400' : 'text-slate-400'
        )}>
          z-score: {d.zscore?.toFixed(2)}
        </div>
      )}
      {d.ff_event && (
        <div className="mt-1.5 pt-1.5 border-t border-slate-700">
          <div className="text-slate-500 text-[10px]">FF Release</div>
          <div className="text-slate-200">{d.ff_event}</div>
          {d.ff_forecast && <div className="text-slate-400">Forecast: {d.ff_forecast}</div>}
          {d.ff_actual   && <div className="text-slate-300">Actual: {d.ff_actual}</div>}
        </div>
      )}
    </div>
  )
}

// ── Direction Icon ─────────────────────────────────────────────────────────────

function DirIcon({ dir }: { dir: string | null }) {
  if (dir === 'bullish') return <TrendingUp size={12} className="text-emerald-400" />
  if (dir === 'bearish') return <TrendingDown size={12} className="text-red-400" />
  return <Minus size={12} className="text-slate-500" />
}

// ── Series Sidebar ─────────────────────────────────────────────────────────────

function SeriesList({
  series,
  selected,
  onSelect,
}: {
  series: SeriesMeta[]
  selected: string
  onSelect: (id: string) => void
}) {
  const grouped = series.reduce<Record<string, SeriesMeta[]>>((acc, s) => {
    if (!acc[s.category]) acc[s.category] = []
    acc[s.category].push(s)
    return acc
  }, {})

  return (
    <div className="flex flex-col gap-3">
      {Object.entries(grouped).map(([cat, items]) => (
        <div key={cat}>
          <div className="text-xs font-semibold uppercase tracking-wider mb-1"
            style={{ color: CATEGORY_COLORS[cat] ?? '#64748b' }}>
            {CATEGORY_LABELS[cat] ?? cat}
          </div>
          <div className="flex flex-col gap-0.5">
            {items.map(s => (
              <button
                key={s.id}
                onClick={() => onSelect(s.id)}
                className={clsx(
                  'text-left px-2.5 py-1.5 rounded text-sm transition-colors',
                  selected === s.id
                    ? 'bg-slate-700 text-white'
                    : 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'
                )}
              >
                {s.name}
                <span className="ml-1.5 text-xs text-slate-600">{s.unit}</span>
              </button>
            ))}
          </div>
        </div>
      ))}
    </div>
  )
}

// ── Events Table ──────────────────────────────────────────────────────────────

function EventsTable({ events, unit }: { events: FFEvent[]; unit: string }) {
  const recent = [...events].reverse().slice(0, 30)
  if (!recent.length) return (
    <div className="text-slate-600 text-sm text-center py-6">
      No FF events linked to this series yet.<br/>
      <span className="text-xs">Import the CSV and run the bootstrap first.</span>
    </div>
  )

  return (
    <div className="overflow-x-auto">
      <table className="w-full text-xs">
        <thead>
          <tr className="text-slate-500 border-b border-slate-800">
            <th className="text-left py-1.5 pr-3">Date</th>
            <th className="text-left py-1.5 pr-3">Event</th>
            <th className="text-right py-1.5 pr-3">Actual</th>
            <th className="text-right py-1.5 pr-3">Forecast</th>
            <th className="text-right py-1.5">Previous</th>
          </tr>
        </thead>
        <tbody>
          {recent.map((ev, i) => {
            const aNum = parseFloat(ev.actual_value ?? '')
            const fNum = parseFloat(ev.forecast_value ?? '')
            const beat = !isNaN(aNum) && !isNaN(fNum) && aNum !== fNum
            const better = beat && aNum > fNum
            return (
              <tr key={i} className="border-b border-slate-800/50 hover:bg-slate-800/30">
                <td className="py-1.5 pr-3 text-slate-400 tabular-nums">{ev.event_date}</td>
                <td className="py-1.5 pr-3 text-slate-300 max-w-[200px] truncate">{ev.event_name}</td>
                <td className={clsx('py-1.5 pr-3 text-right tabular-nums font-medium',
                  beat ? (better ? 'text-emerald-400' : 'text-red-400') : 'text-slate-200')}>
                  {ev.actual_value ?? '—'}
                </td>
                <td className="py-1.5 pr-3 text-right tabular-nums text-slate-400">
                  {ev.forecast_value ?? '—'}
                </td>
                <td className="py-1.5 text-right tabular-nums text-slate-500">
                  {ev.previous_value ?? '—'}
                </td>
              </tr>
            )
          })}
        </tbody>
      </table>
    </div>
  )
}

// ── Main Page ─────────────────────────────────────────────────────────────────

export default function MacroSeriesPage() {
  const [seriesList, setSeriesList] = useState<SeriesMeta[]>([])
  const [selectedId, setSelectedId]   = useState<string>('PAYEMS')
  const [range, setRange]             = useState('5y')
  const [history, setHistory]         = useState<SeriesHistory | null>(null)
  const [logEntries, setLogEntries]     = useState<LogEntry[]>([])
  const [loading, setLoading]           = useState(false)
  const [backfilling, setBackfilling]   = useState(false)
  const [tab, setTab]                   = useState<'chart' | 'log'>('chart')
  const [selectedEventDate, setSelectedEventDate] = useState<string | null>(null)

  useEffect(() => {
    fetch(`${API}/api/eco/series`).then(r => r.json()).then(setSeriesList).catch(() => {})
  }, [])

  const loadHistory = useCallback(async () => {
    if (!selectedId) return
    setLoading(true)
    try {
      const months = RANGE_OPTIONS.find(r => r.key === range)?.months ?? 60
      const from = fromDateForRange(months)
      const [hist, log] = await Promise.all([
        fetch(`${API}/api/eco/series/${selectedId}/history?from_date=${from}`).then(x => x.json()),
        fetch(`${API}/api/eco/series-log?series_id=${selectedId}&from_date=${from}&limit=1000`).then(x => x.json()),
      ])
      setHistory(hist)
      setLogEntries(Array.isArray(log) ? log : [])
    } catch {}
    finally { setLoading(false) }
  }, [selectedId, range])

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

  const handleBackfill = async () => {
    setBackfilling(true)
    try {
      await fetch(`${API}/api/eco/series-log/backfill`, { method: 'POST' })
      await loadHistory()
    } catch {}
    finally { setBackfilling(false) }
  }

  const color = CATEGORY_COLORS[history?.category ?? ''] ?? '#3b82f6'

  // ── Chart 1 : Actual vs Forecast — source unique ff_calendar (même échelle) ──
  // FRED timeseries (level) ≠ FF change mensuelle → on utilise UNIQUEMENT ff_calendar
  const chartDataFF = (() => {
    if (!history) return []
    // Déduplique par event_date : garde le premier event du jour (NFP, pas ADP)
    const seen = new Set<string>()
    return history.events
      .filter(ev => { if (seen.has(ev.event_date)) return false; seen.add(ev.event_date); return true })
      .map(ev => {
        const actual   = ev.actual_value   ? parseFloat(ev.actual_value)   || null : null
        const forecast = ev.forecast_value ? parseFloat(ev.forecast_value) || null : null
        const isFuture = actual == null
        return {
          event_date: ev.event_date,
          label:      fmtDate(ev.event_date),
          actual,
          forecast,
          isFuture,
          event_name: ev.event_name,
        }
      })
  })()

  // ── Chart 2 : Évolution du forecast — source macro_series_log ──────────────
  // Groupe par event_date → pour chaque release, une courbe chronologique du forecast
  const forecastEvolution = (() => {
    if (!logEntries.length) return { byDate: {}, allDates: [] as string[], allTimes: [] as string[] }
    const byDate: Record<string, { time: string; forecast: number | null; actual: number | null }[]> = {}
    for (const e of logEntries) {
      if (!byDate[e.event_date]) byDate[e.event_date] = []
      byDate[e.event_date].push({
        time:     e.logged_at.slice(0, 16),
        forecast: e.forecast_value,
        actual:   e.actual_value,
      })
    }
    // Sort each series by logged_at
    for (const k of Object.keys(byDate)) byDate[k].sort((a, b) => a.time.localeCompare(b.time))
    const allDates = Object.keys(byDate).sort()
    // Collect all unique logged_at times across all event_dates for a unified X-axis
    const timesSet = new Set<string>()
    for (const pts of Object.values(byDate)) pts.forEach(p => timesSet.add(p.time))
    const allTimes = [...timesSet].sort()
    return { byDate, allDates, allTimes }
  })()

  // Build unified forecast evolution chart data (X = logged_at, Y = forecast per release)
  const evoChartData = forecastEvolution.allTimes.map(t => {
    const row: Record<string, number | string | null> = { time: t.slice(0, 10) }
    for (const d of forecastEvolution.allDates) {
      const pts = forecastEvolution.byDate[d]
      // Last known forecast at time t
      const last = [...pts].reverse().find(p => p.time <= t)
      row[d] = last?.forecast ?? null
    }
    return row
  })

  // Stats from FF data (not FRED level)
  const ffActuals = chartDataFF.map(d => d.actual).filter((v): v is number => v !== null)
  const latest = ffActuals[ffActuals.length - 1] ?? null
  const prev   = ffActuals[ffActuals.length - 2] ?? null
  const minVal = ffActuals.length ? Math.min(...ffActuals) : null
  const maxVal = ffActuals.length ? Math.max(...ffActuals) : null
  const trend  = latest !== null && prev !== null ? (latest > prev ? 1 : latest < prev ? -1 : 0) : 0

  const EVO_COLORS = ['#f59e0b', '#38bdf8', '#a78bfa', '#34d399', '#fb923c', '#f472b6']

  // Compute focused event date for the Log tab (used by both chart and table)
  const logFocusDate = (() => {
    if (!forecastEvolution.allDates.length) return null
    const today = new Date().toISOString().slice(0, 10)
    const twelveMonthsAgo = new Date(); twelveMonthsAgo.setFullYear(twelveMonthsAgo.getFullYear() - 1)
    const cutoff = twelveMonthsAgo.toISOString().slice(0, 10)
    const upcoming   = forecastEvolution.allDates.filter(d => d >= today).sort()
    const recentPast = forecastEvolution.allDates.filter(d => d >= cutoff && d < today).sort().reverse()
    const ordered    = [...upcoming, ...recentPast]
    return selectedEventDate ?? ordered[0] ?? null
  })()

  return (
    <div className="flex h-full overflow-hidden" style={{ minHeight: 0 }}>
      {/* Sidebar */}
      <div className="w-56 shrink-0 bg-slate-900 border-r border-slate-800 overflow-y-auto p-3">
        <div className="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">
          FRED Series
        </div>
        <SeriesList
          series={seriesList}
          selected={selectedId}
          onSelect={id => { setSelectedId(id); setHistory(null) }}
        />
      </div>

      {/* Main content */}
      <div className="flex-1 overflow-y-auto p-4 space-y-4">
        {/* Header */}
        <div className="flex items-start justify-between flex-wrap gap-3">
          <div>
            <h1 className="text-xl font-bold text-white">
              {history?.name ?? selectedId}
            </h1>
            <div className="text-slate-500 text-xs mt-0.5">
              {history?.category && (
                <span className="mr-2" style={{ color }}>
                  {CATEGORY_LABELS[history.category]}
                </span>
              )}
              {history?.freq} · FRED/{selectedId}
            </div>
          </div>

          <div className="flex items-center gap-2">
            {/* Tab selector */}
            <div className="flex gap-1 bg-slate-800 rounded p-0.5">
              {(['chart', 'log'] as const).map(t => (
                <button key={t} onClick={() => setTab(t)}
                  className={clsx('px-2.5 py-1 rounded text-xs font-medium transition-colors',
                    tab === t ? 'bg-slate-600 text-white' : 'text-slate-400 hover:text-slate-200')}>
                  {t === 'chart' ? 'Chart' : `Log (${logEntries.length})`}
                </button>
              ))}
            </div>
            {/* Range selector */}
            <div className="flex gap-1 bg-slate-800 rounded p-0.5">
              {RANGE_OPTIONS.map(r => (
                <button key={r.key} onClick={() => setRange(r.key)}
                  className={clsx('px-2.5 py-1 rounded text-xs font-medium transition-colors',
                    range === r.key ? 'bg-slate-600 text-white' : 'text-slate-400 hover:text-slate-200')}>
                  {r.label}
                </button>
              ))}
            </div>
            <button onClick={handleBackfill} disabled={backfilling}
              title="Importer l'historique ff_calendar → macro_series_log"
              className="p-1.5 rounded bg-slate-700 hover:bg-slate-600 disabled:opacity-50">
              <Database size={13} className={clsx(backfilling && 'animate-pulse')} />
            </button>
            <button onClick={loadHistory} disabled={loading}
              className="p-1.5 rounded bg-slate-700 hover:bg-slate-600 disabled:opacity-50">
              <RefreshCw size={13} className={clsx(loading && 'animate-spin')} />
            </button>
          </div>
        </div>

        {/* KPI cards */}
        {history && ffActuals.length > 0 && (
          <div className="grid grid-cols-4 gap-3">
            {[
              {
                label: 'Latest',
                value: fmtVal(latest, history.unit),
                sub: (() => { const a = chartDataFF.filter(d => d.actual != null); return a[a.length - 1]?.event_date })(),
                accent: trend === 1 ? 'text-emerald-400' : trend === -1 ? 'text-red-400' : 'text-slate-200',
                icon: trend === 1 ? <TrendingUp size={14}/> : trend === -1 ? <TrendingDown size={14}/> : <Minus size={14}/>,
              },
              { label: 'Previous', value: fmtVal(prev, history.unit), sub: (() => { const a = chartDataFF.filter(d => d.actual != null); return a[a.length - 2]?.event_date })(), accent: 'text-slate-300', icon: null },
              { label: 'Min (period)', value: fmtVal(minVal, history.unit), sub: null, accent: 'text-sky-400', icon: null },
              { label: 'Max (period)', value: fmtVal(maxVal, history.unit), sub: null, accent: 'text-amber-400', icon: null },
            ].map(card => (
              <div key={card.label} className="bg-slate-800 rounded-lg p-3 border border-slate-700">
                <div className="text-slate-500 text-xs mb-1">{card.label}</div>
                <div className={clsx('text-base font-bold flex items-center gap-1', card.accent)}>
                  {card.icon}{card.value}
                </div>
                {card.sub && <div className="text-slate-600 text-xs mt-0.5">{card.sub}</div>}
              </div>
            ))}
          </div>
        )}

        {tab === 'chart' && (
        <div className="bg-slate-800 rounded-lg border border-slate-700 p-4">
          <div className="flex items-center justify-between mb-3">
            <span className="text-sm font-medium text-slate-300">
              Actual vs Consensus
              {history && <span className="text-slate-500 text-xs ml-2">({chartDataFF.length} releases)</span>}
            </span>
            <span className="text-xs text-slate-500">source: ff_calendar</span>
          </div>

          {loading && <div className="h-64 flex items-center justify-center text-slate-600 text-sm">Chargement…</div>}
          {!loading && chartDataFF.length === 0 && (
            <div className="h-64 flex items-center justify-center text-slate-600 text-sm">
              Pas de données — aucun event ff_calendar lié à cette série.
            </div>
          )}

          {!loading && chartDataFF.length > 0 && (
            <ResponsiveContainer width="100%" height={300}>
              <ComposedChart data={chartDataFF} margin={{ top: 4, right: 16, bottom: 4, left: 0 }}>
                <defs>
                  <linearGradient id={`grad-${selectedId}`} x1="0" y1="0" x2="0" y2="1">
                    <stop offset="5%"  stopColor={color} stopOpacity={0.3} />
                    <stop offset="95%" stopColor={color} stopOpacity={0} />
                  </linearGradient>
                </defs>
                <CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
                <XAxis dataKey="label" tick={{ fontSize: 10, fill: '#64748b' }} interval="preserveStartEnd" tickLine={false} />
                <YAxis tick={{ fontSize: 10, fill: '#64748b' }} tickLine={false} axisLine={false} width={50} />
                <Tooltip content={({ active, payload }) => {
                  if (!active || !payload?.length) return null
                  const d = payload[0].payload
                  return (
                    <div className="bg-slate-900 border border-slate-600 rounded p-2.5 text-xs shadow-xl">
                      <div className="text-slate-400 mb-1">{d.event_date}</div>
                      <div className="text-slate-300 text-[10px] mb-1.5">{d.event_name}</div>
                      {d.actual != null && <div className="text-white font-semibold">Actual: {d.actual?.toFixed(2)} {history?.unit}</div>}
                      {d.forecast != null && <div className="text-amber-400">Forecast: {d.forecast?.toFixed(2)} {history?.unit}</div>}
                      {d.isFuture && <div className="text-slate-500 italic">— à venir —</div>}
                    </div>
                  )
                }} />
                <Legend wrapperStyle={{ fontSize: 11, color: '#94a3b8' }} />

                {minVal !== null && maxVal !== null && minVal < 0 && maxVal > 0 && (
                  <ReferenceLine y={0} stroke="#475569" strokeDasharray="4 2" />
                )}

                {/* Actual — area + line (only past points with actual) */}
                <Area type="monotone" dataKey="actual" name="Actual"
                  stroke={color} strokeWidth={2} fill={`url(#grad-${selectedId})`}
                  dot={false} activeDot={{ r: 4, fill: color }} connectNulls />

                {/* Forecast — dashed line (including future) */}
                <Line type="monotone" dataKey="forecast" name="Forecast"
                  stroke="#f59e0b" strokeWidth={1.5} strokeDasharray="4 3"
                  dot={false} activeDot={{ r: 3 }} connectNulls />
              </ComposedChart>
            </ResponsiveContainer>
          )}
        </div>
        )}

        {tab === 'log' && (
        <div className="bg-slate-800 rounded-lg border border-slate-700 p-4">
          <div className="flex items-center justify-between mb-3">
            <span className="text-sm font-medium text-slate-300">
              Journal des changements — {selectedId}
              {logFocusDate && <span className="text-slate-400 text-xs ml-2">· release {logFocusDate}</span>}
              <span className="text-slate-500 text-xs ml-2">
                ({logFocusDate
                  ? logEntries.filter(e => e.event_date === logFocusDate).length
                  : logEntries.length} entrées)
              </span>
            </span>
            {logEntries.length === 0 && (
              <button onClick={handleBackfill} disabled={backfilling}
                className="text-xs text-violet-400 hover:text-violet-200 bg-violet-900/20 border border-violet-800/40 rounded px-2 py-1 disabled:opacity-50">
                {backfilling ? 'Import…' : 'Importer historique ff_calendar'}
              </button>
            )}
          </div>
          {/* Forecast evolution — focus one release at a time */}
          {forecastEvolution.allDates.length > 0 && (() => {
            const today = new Date().toISOString().slice(0, 10)
            const twelveMonthsAgo = new Date(); twelveMonthsAgo.setFullYear(twelveMonthsAgo.getFullYear() - 1)
            const cutoff = twelveMonthsAgo.toISOString().slice(0, 10)
            const upcoming   = forecastEvolution.allDates.filter(d => d >= today).sort()
            const recentPast = forecastEvolution.allDates.filter(d => d >= cutoff && d < today).sort().reverse()
            const ordered    = [...upcoming, ...recentPast]
            const focusDate = selectedEventDate ?? ordered[0] ?? null
            if (!focusDate) return null

            const allPts = forecastEvolution.byDate[focusDate] ?? []
            // Keep only the 4 weeks window before event_date
            const windowStart = new Date(focusDate)
            windowStart.setDate(windowStart.getDate() - 28)
            const windowStr = windowStart.toISOString().slice(0, 16)
            const pts = allPts.filter(p => p.time >= windowStr)
            const chartPts = pts.map(p => ({ time: p.time.slice(0, 10), forecast: p.forecast, actual: p.actual }))
            const hasActual = pts.some(p => p.actual != null)
            const actualVal = pts.find(p => p.actual != null)?.actual ?? null

            return (
              <div className="mb-5">
                {/* Release selector chips */}
                <div className="flex items-center gap-1.5 flex-wrap mb-3">
                  <span className="text-xs text-slate-500 shrink-0">Release :</span>
                  {ordered.slice(0, 12).map(d => {
                    const isUpcoming = d >= today
                    const isFocus = d === focusDate
                    return (
                      <button key={d} onClick={() => setSelectedEventDate(d)}
                        className={clsx(
                          'px-2 py-0.5 rounded text-xs font-mono transition-colors border',
                          isFocus
                            ? 'bg-blue-600 border-blue-500 text-white'
                            : isUpcoming
                            ? 'bg-amber-900/30 border-amber-700/50 text-amber-400 hover:bg-amber-800/40'
                            : 'bg-slate-700/40 border-slate-700 text-slate-400 hover:bg-slate-700'
                        )}>
                        {d}
                        {isUpcoming && <span className="ml-1 text-[9px] opacity-70">↑</span>}
                      </button>
                    )
                  })}
                  {ordered.length > 12 && (
                    <span className="text-xs text-slate-600">+{ordered.length - 12} autres</span>
                  )}
                </div>

                <div className="text-xs text-slate-500 mb-2">
                  Évolution du forecast — release du <span className="text-slate-300">{focusDate}</span>
                  {pts.length === 0
                    ? ' — aucune révision détectée (syncs insuffisants)'
                    : ` — ${pts.length} entrée${pts.length > 1 ? 's' : ''}, fenêtre 4 semaines`}
                </div>

                {chartPts.length === 0 ? (
                  <div className="h-24 flex items-center justify-center text-slate-600 text-xs">
                    Les révisions apparaîtront après plusieurs syncs 6h consécutifs.
                  </div>
                ) : (
                  <ResponsiveContainer width="100%" height={200}>
                    <ComposedChart data={chartPts} margin={{ top: 4, right: 16, bottom: 4, left: 0 }}>
                      <CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
                      <XAxis dataKey="time" tick={{ fontSize: 9, fill: '#64748b' }} interval="preserveStartEnd" tickLine={false} />
                      <YAxis tick={{ fontSize: 9, fill: '#64748b' }} tickLine={false} axisLine={false} width={45}
                        tickFormatter={v => `${v}${history?.unit ?? ''}`} />
                      <Tooltip content={({ active, payload }) => {
                        if (!active || !payload?.length) return null
                        const d = payload[0]?.payload
                        return (
                          <div className="bg-slate-900 border border-slate-600 rounded p-2 text-xs shadow-xl">
                            <div className="text-slate-400 mb-1">{d.time}</div>
                            {d.forecast != null && <div className="text-amber-400">Forecast: {d.forecast} {history?.unit}</div>}
                            {d.actual  != null && <div className="text-emerald-400 font-semibold">Actual: {d.actual} {history?.unit}</div>}
                          </div>
                        )
                      }} />
                      <Line type="stepAfter" dataKey="forecast" name="Forecast"
                        stroke="#f59e0b" strokeWidth={2} dot={{ r: 3, fill: '#f59e0b' }} connectNulls />
                      {hasActual && (
                        <ReferenceLine y={actualVal!} stroke="#34d399" strokeWidth={1.5}
                          strokeDasharray="5 3" label={{ value: `Actual ${actualVal}`, fill: '#34d399', fontSize: 10, position: 'insideTopRight' }} />
                      )}
                    </ComposedChart>
                  </ResponsiveContainer>
                )}
              </div>
            )
          })()}

          {logEntries.length === 0 ? (
            <div className="text-slate-600 text-sm text-center py-8">
              Aucune entrée — cliquez "Importer historique" ou attendez le prochain sync (6h).
            </div>
          ) : (
            <div className="overflow-x-auto">
              <table className="w-full text-xs">
                <thead>
                  <tr className="text-slate-500 border-b border-slate-800">
                    <th className="text-left py-1.5 pr-3">Release</th>
                    <th className="text-left py-1.5 pr-3">Capturé à</th>
                    <th className="text-right py-1.5 pr-3">Actual</th>
                    <th className="text-right py-1.5 pr-3">Forecast</th>
                    <th className="text-right py-1.5 pr-3">Previous</th>
                    <th className="text-left py-1.5">Changement</th>
                  </tr>
                </thead>
                <tbody>
                  {[...logEntries].filter(e => !logFocusDate || e.event_date === logFocusDate).reverse().map((e, i) => {
                    const isActual = e.actual_value != null
                    const isForecastChange = e.changed === 'forecast' || e.changed === 'both'
                    return (
                      <tr key={i} className={clsx('border-b border-slate-800/50 hover:bg-slate-800/30',
                        isActual ? 'bg-slate-800/20' : '')}>
                        <td className="py-1.5 pr-3 text-slate-400 tabular-nums">{e.event_date}</td>
                        <td className="py-1.5 pr-3 text-slate-600 tabular-nums">{e.logged_at.slice(0, 16)}</td>
                        <td className={clsx('py-1.5 pr-3 text-right tabular-nums font-medium',
                          isActual ? 'text-white' : 'text-slate-700')}>
                          {e.actual_value != null ? e.actual_value.toFixed(2) : '—'}
                        </td>
                        <td className={clsx('py-1.5 pr-3 text-right tabular-nums',
                          isForecastChange ? 'text-amber-400' : 'text-slate-400')}>
                          {e.forecast_value != null ? e.forecast_value.toFixed(2) : '—'}
                        </td>
                        <td className="py-1.5 pr-3 text-right tabular-nums text-slate-600">
                          {e.previous_value != null ? e.previous_value.toFixed(2) : '—'}
                        </td>
                        <td className="py-1.5">
                          <span className={clsx('px-1.5 py-0.5 rounded text-[10px]',
                            e.changed === 'actual' || e.changed === 'both' ? 'bg-emerald-900/40 text-emerald-400' :
                            e.changed === 'forecast' ? 'bg-amber-900/40 text-amber-400' :
                            'bg-slate-700/40 text-slate-500')}>
                            {e.changed}
                          </span>
                        </td>
                      </tr>
                    )
                  })}
                </tbody>
              </table>
            </div>
          )}
        </div>
        )}

        {/* Events table */}
        <div className="bg-slate-800 rounded-lg border border-slate-700 p-4">
          <div className="text-sm font-medium text-slate-300 mb-3">
            FF Calendar Events
            {history && <span className="text-slate-500 text-xs ml-2">({history.events.length} liés)</span>}
          </div>
          {history && <EventsTable events={history.events} unit={history.unit} />}
        </div>

        {/* Z-score context */}
        {history && history.timeseries.some(d => d.surprise_zscore !== null) && (
          <div className="bg-slate-800 rounded-lg border border-slate-700 p-4">
            <div className="text-sm font-medium text-slate-300 mb-3">Recent Surprises (FRED z-score)</div>
            <div className="flex flex-col gap-1">
              {history.timeseries
                .filter(d => d.surprise_zscore !== null && d.surprise_zscore !== 0)
                .slice(-15)
                .reverse()
                .map((d, i) => (
                  <div key={i} className="flex items-center gap-2 text-xs">
                    <span className="text-slate-500 w-24 tabular-nums shrink-0">{d.event_date}</span>
                    <DirIcon dir={d.surprise_direction} />
                    <div className="flex-1 bg-slate-700 rounded-full h-1.5 overflow-hidden">
                      <div
                        className={clsx(
                          'h-full rounded-full',
                          d.surprise_direction === 'bullish' ? 'bg-emerald-500' :
                          d.surprise_direction === 'bearish' ? 'bg-red-500' : 'bg-slate-500'
                        )}
                        style={{ width: `${Math.min(100, Math.abs(d.surprise_zscore!) * 25)}%` }}
                      />
                    </div>
                    <span className={clsx(
                      'w-12 text-right tabular-nums',
                      d.surprise_direction === 'bullish' ? 'text-emerald-400' :
                      d.surprise_direction === 'bearish' ? 'text-red-400' : 'text-slate-400'
                    )}>
                      {d.surprise_zscore!.toFixed(2)}σ
                    </span>
                    <span className="text-slate-500 tabular-nums">
                      {d.actual_value?.toFixed(2)} {history.unit}
                    </span>
                  </div>
                ))}
            </div>
          </div>
        )}
      </div>
    </div>
  )
}
