import { useState, useEffect, useCallback } from 'react'
import {
  useAllDeskConfigs, useAllSpecialistReports,
  useUpdateDeskConfig, useCreateSpecialistReport,
  useUpdateSpecialistReport, useDeleteSpecialistReport,
  useLinkReportDesk, useUnlinkReportDesk,
  useCotData, useFetchCot, useForwardCurves, useFetchForwardCurves,
  useUpdateReportResult, useScoreText,
  DeskConfig, SpecialistReport, MacroSensitivity,
  TextSentimentResult, ReportResultUpdate,
} from '../hooks/useApi'
import {
  Users, FileText, Plus, Trash2, Save, X, Edit2,
  ChevronRight, Star, Link, ExternalLink, RefreshCw,
  AlertCircle, Calendar, BookOpen,
  TrendingUp, TrendingDown, Minus, BarChart2, FlaskConical,
  ArrowUp, ArrowDown, Activity, Landmark, Play, Send,
} from 'lucide-react'
import clsx from 'clsx'

const CADENCE_OPTIONS = ['daily', 'weekly', 'bi-weekly', 'monthly', '6-weekly', 'quarterly', 'annual', 'irregular']
const DESK_ORDER = ['forex', 'metals', 'agri', 'energy', 'indices', 'crypto', 'bonds']

// ── Importance stars ───────────────────────────────────────────────────────────

function Stars({ n, onChange }: { n: number; onChange?: (v: number) => void }) {
  return (
    <span className="flex gap-0.5">
      {[1, 2, 3].map(i => (
        <Star
          key={i}
          onClick={() => onChange?.(i)}
          className={clsx('w-3.5 h-3.5 transition-colors',
            i <= n ? 'text-amber-400 fill-amber-400' : 'text-slate-700',
            onChange && 'cursor-pointer hover:text-amber-300')}
        />
      ))}
    </span>
  )
}

// ── Report modal ───────────────────────────────────────────────────────────────

function ReportModal({
  initial, allDesks, onSave, onClose,
}: {
  initial?: SpecialistReport & { desks?: string[] }
  allDesks: DeskConfig[]
  onSave: (data: any) => void
  onClose: () => void
}) {
  const [name, setName]         = useState(initial?.name ?? '')
  const [source, setSource]     = useState(initial?.source ?? '')
  const [cadence, setCadence]   = useState(initial?.cadence ?? 'monthly')
  const [nextDate, setNextDate] = useState(initial?.next_date ?? '')
  const [lastDate, setLastDate] = useState(initial?.last_date ?? '')
  const [importance, setImp]    = useState(initial?.importance ?? 2)
  const [notes, setNotes]       = useState(initial?.notes ?? '')
  const [url, setUrl]           = useState(initial?.url ?? '')
  const [desks, setDesks]       = useState<string[]>(initial?.desks ?? [])

  const toggleDesk = (ac: string) =>
    setDesks(d => d.includes(ac) ? d.filter(x => x !== ac) : [...d, ac])

  const handleSave = () => {
    if (!name.trim()) return
    onSave({ name: name.trim(), source, cadence, next_date: nextDate || null, last_date: lastDate || null, importance, notes, url, desks })
  }

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
      <div className="w-[520px] bg-dark-800 border border-slate-700/60 rounded-xl shadow-2xl overflow-hidden">
        {/* Header */}
        <div className="flex items-center justify-between px-5 py-4 border-b border-slate-700/40">
          <div className="flex items-center gap-2">
            <FileText className="w-4 h-4 text-violet-400" />
            <span className="font-semibold text-slate-100 text-sm">
              {initial ? 'Edit Report' : 'New Report'}
            </span>
          </div>
          <button onClick={onClose} className="text-slate-500 hover:text-slate-300 transition-colors">
            <X className="w-4 h-4" />
          </button>
        </div>

        {/* Body */}
        <div className="p-5 space-y-4 max-h-[70vh] overflow-y-auto">
          {/* Name + Source */}
          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="text-[10px] text-slate-500 uppercase tracking-wide mb-1 block">Report name *</label>
              <input value={name} onChange={e => setName(e.target.value)}
                placeholder="Cocoa Grinding Report"
                className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-200 focus:outline-none focus:border-violet-500" />
            </div>
            <div>
              <label className="text-[10px] text-slate-500 uppercase tracking-wide mb-1 block">Source / Issuer</label>
              <input value={source} onChange={e => setSource(e.target.value)}
                placeholder="ICCO, USDA, CFTC…"
                className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-200 focus:outline-none focus:border-violet-500" />
            </div>
          </div>

          {/* Cadence + Importance */}
          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="text-[10px] text-slate-500 uppercase tracking-wide mb-1 block">Cadence</label>
              <select value={cadence} onChange={e => setCadence(e.target.value)}
                className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-200 focus:outline-none focus:border-violet-500">
                {CADENCE_OPTIONS.map(c => <option key={c} value={c}>{c}</option>)}
              </select>
            </div>
            <div>
              <label className="text-[10px] text-slate-500 uppercase tracking-wide mb-1 block">Importance</label>
              <div className="flex items-center gap-2 pt-2">
                <Stars n={importance} onChange={setImp} />
                <span className="text-[10px] text-slate-500">{importance === 3 ? 'High' : importance === 2 ? 'Medium' : 'Low'}</span>
              </div>
            </div>
          </div>

          {/* Dates */}
          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="text-[10px] text-slate-500 uppercase tracking-wide mb-1 block">Next release date</label>
              <input type="date" value={nextDate} onChange={e => setNextDate(e.target.value)}
                className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-200 focus:outline-none focus:border-violet-500" />
            </div>
            <div>
              <label className="text-[10px] text-slate-500 uppercase tracking-wide mb-1 block">Last release date</label>
              <input type="date" value={lastDate} onChange={e => setLastDate(e.target.value)}
                className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-200 focus:outline-none focus:border-violet-500" />
            </div>
          </div>

          {/* URL */}
          <div>
            <label className="text-[10px] text-slate-500 uppercase tracking-wide mb-1 block">URL (optional)</label>
            <input value={url} onChange={e => setUrl(e.target.value)}
              placeholder="https://…"
              className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-200 focus:outline-none focus:border-violet-500" />
          </div>

          {/* Notes */}
          <div>
            <label className="text-[10px] text-slate-500 uppercase tracking-wide mb-1 block">Notes</label>
            <textarea value={notes} onChange={e => setNotes(e.target.value)} rows={2}
              placeholder="Market impact context, watch for…"
              className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-300 focus:outline-none focus:border-violet-500 resize-none" />
          </div>

          {/* Desk assignment */}
          <div>
            <label className="text-[10px] text-slate-500 uppercase tracking-wide mb-2 block">Assign to desks</label>
            <div className="flex flex-wrap gap-2">
              {DESK_ORDER.map(ac => {
                const desk = allDesks.find(d => d.asset_class === ac)
                if (!desk) return null
                const active = desks.includes(ac)
                return (
                  <button key={ac} onClick={() => toggleDesk(ac)}
                    className={clsx(
                      'flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs border transition-colors',
                      active
                        ? 'bg-violet-700 border-violet-500 text-white'
                        : 'border-slate-700 text-slate-500 hover:text-slate-300 hover:border-slate-500'
                    )}>
                    <span>{desk.icon}</span>
                    <span>{desk.display_name}</span>
                  </button>
                )
              })}
            </div>
          </div>
        </div>

        {/* Footer */}
        <div className="px-5 py-3 border-t border-slate-700/40 flex justify-end gap-2">
          <button onClick={onClose}
            className="px-3 py-1.5 text-xs text-slate-400 hover:text-slate-200 transition-colors">
            Cancel
          </button>
          <button onClick={handleSave} disabled={!name.trim()}
            className="flex items-center gap-1.5 px-4 py-1.5 bg-violet-700 hover:bg-violet-600 disabled:opacity-40 text-white text-xs font-semibold rounded transition-colors">
            <Save className="w-3.5 h-3.5" /> Save
          </button>
        </div>
      </div>
    </div>
  )
}

// ── Macro sensitivity row editor ───────────────────────────────────────────────

function MacroSensitivityEditor({
  items, onChange,
}: { items: MacroSensitivity[]; onChange: (v: MacroSensitivity[]) => void }) {
  const [regime, setRegime]   = useState('')
  const [effect, setEffect]   = useState('')

  const add = () => {
    if (!regime.trim() || !effect.trim()) return
    onChange([...items, { regime: regime.trim(), effect: effect.trim() }])
    setRegime(''); setEffect('')
  }

  return (
    <div className="space-y-2">
      {items.map((s, i) => (
        <div key={i} className="flex items-center gap-2 bg-dark-700/60 rounded px-2 py-1.5 text-xs">
          <span className="font-mono text-violet-300 min-w-[120px] truncate">{s.regime}</span>
          <ChevronRight className="w-3 h-3 text-slate-600 flex-shrink-0" />
          <span className="text-slate-300 flex-1 truncate">{s.effect}</span>
          <button onClick={() => onChange(items.filter((_, j) => j !== i))}
            className="text-slate-600 hover:text-red-400 transition-colors flex-shrink-0">
            <X className="w-3 h-3" />
          </button>
        </div>
      ))}
      <div className="flex gap-2">
        <input value={regime} onChange={e => setRegime(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && add()}
          placeholder="regime (e.g. risk_off)"
          className="w-36 px-2 py-1 text-xs bg-dark-700 border border-slate-700/50 rounded text-slate-300 placeholder-slate-600 focus:outline-none focus:border-violet-500 font-mono" />
        <input value={effect} onChange={e => setEffect(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && add()}
          placeholder="effect on this asset class"
          className="flex-1 px-2 py-1 text-xs bg-dark-700 border border-slate-700/50 rounded text-slate-300 placeholder-slate-600 focus:outline-none focus:border-violet-500" />
        <button onClick={add} disabled={!regime.trim() || !effect.trim()}
          className="px-2 py-1 bg-violet-800 hover:bg-violet-700 disabled:opacity-30 text-white rounded text-xs transition-colors">
          <Plus className="w-3 h-3" />
        </button>
      </div>
    </div>
  )
}

// ── Surprise Index inline component ───────────────────────────────────────────

function SurpriseInput({ report, onSave }: {
  report: any
  onSave: (data: ReportResultUpdate) => void
}) {
  const [consensus, setConsensus] = useState<string>(report.consensus_estimate?.toString() ?? '')
  const [actual, setActual]       = useState<string>(report.actual_value?.toString() ?? '')
  const [open, setOpen]           = useState(false)

  const surprise = actual !== '' && consensus !== ''
    ? parseFloat(actual) - parseFloat(consensus)
    : null

  return (
    <div className="mt-1">
      {!open && (
        <button onClick={() => setOpen(true)} className="text-[10px] text-slate-600 hover:text-slate-400 transition-colors flex items-center gap-1">
          <FlaskConical className="w-2.5 h-2.5" />
          {report.surprise_score != null
            ? <span className={clsx('font-mono', report.surprise_score > 0 ? 'text-emerald-500' : 'text-red-500')}>
                surprise: {report.surprise_score >= 0 ? '+' : ''}{report.surprise_score}
              </span>
            : 'Add consensus / actual'}
        </button>
      )}
      {open && (
        <div className="mt-2 space-y-1.5 bg-dark-700/60 rounded p-2 border border-slate-700/40">
          <div className="flex gap-2">
            <div className="flex-1">
              <div className="text-[9px] text-slate-600 mb-0.5">Consensus</div>
              <input value={consensus} onChange={e => setConsensus(e.target.value)} type="number" step="any"
                placeholder="0.0"
                className="w-full px-2 py-1 text-[10px] bg-dark-800 border border-slate-600/50 rounded text-slate-300 focus:outline-none focus:border-violet-500 font-mono" />
            </div>
            <div className="flex-1">
              <div className="text-[9px] text-slate-600 mb-0.5">Actual</div>
              <input value={actual} onChange={e => setActual(e.target.value)} type="number" step="any"
                placeholder="0.0"
                className="w-full px-2 py-1 text-[10px] bg-dark-800 border border-slate-600/50 rounded text-slate-300 focus:outline-none focus:border-violet-500 font-mono" />
            </div>
            {surprise !== null && (
              <div className="flex-1">
                <div className="text-[9px] text-slate-600 mb-0.5">Surprise</div>
                <div className={clsx('px-2 py-1 text-[10px] font-mono font-bold rounded border',
                  surprise > 0 ? 'text-emerald-400 border-emerald-800/40 bg-emerald-900/20' :
                  surprise < 0 ? 'text-red-400 border-red-800/40 bg-red-900/20' :
                  'text-slate-400 border-slate-700/40')}>
                  {surprise >= 0 ? '+' : ''}{surprise.toFixed(3)}
                </div>
              </div>
            )}
          </div>
          <div className="flex gap-2 justify-end">
            <button onClick={() => setOpen(false)} className="text-[10px] text-slate-600 hover:text-slate-400 transition-colors">Cancel</button>
            <button
              onClick={() => {
                onSave({
                  consensus_estimate: consensus !== '' ? parseFloat(consensus) : null,
                  actual_value: actual !== '' ? parseFloat(actual) : null,
                })
                setOpen(false)
              }}
              className="px-2 py-0.5 bg-violet-800 hover:bg-violet-700 text-white text-[10px] rounded transition-colors">
              Save
            </button>
          </div>
        </div>
      )}
    </div>
  )
}

// ── Bank Forecasts Panel ───────────────────────────────────────────────────────

interface BankSource { id: string; name: string; url: string; active: number; last_scraped: string | null; notes: string }
interface BankForecast { id: number; source_id: string; bank_name: string; series_id: string; event_name: string; event_date: string; forecast_value: number | null; unit: string; confidence: string; snippet: string; extracted_at: string }
interface Consensus { series_id: string; event_name: string; event_date: string; consensus: number; bank_count: number; min_forecast: number; max_forecast: number }

function BankForecastsPanel() {
  const [sources, setSources]     = useState<BankSource[]>([])
  const [forecasts, setForecasts] = useState<BankForecast[]>([])
  const [consensus, setConsensus] = useState<Consensus[]>([])
  const [scraping, setScraping]   = useState(false)
  const [pushing, setPushing]     = useState(false)
  const [editId, setEditId]       = useState<string | null>(null)
  const [editUrl, setEditUrl]     = useState('')
  const [editNotes, setEditNotes] = useState('')
  const [scrapeResults, setScrapeResults] = useState<any[]>([])

  const load = useCallback(async () => {
    const [s, f, c] = await Promise.all([
      fetch('/api/specialist-desks/bank-forecasts/sources').then(r => r.json()),
      fetch('/api/specialist-desks/bank-forecasts').then(r => r.json()),
      fetch('/api/specialist-desks/bank-forecasts/consensus').then(r => r.json()),
    ])
    setSources(Array.isArray(s) ? s : [])
    setForecasts(Array.isArray(f) ? f : [])
    setConsensus(Array.isArray(c) ? c : [])
  }, [])

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

  const saveSource = async (src: BankSource) => {
    await fetch(`/api/specialist-desks/bank-forecasts/sources/${src.id}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: src.name, url: editUrl, active: !!src.active, notes: editNotes }),
    })
    setEditId(null)
    load()
  }

  const scrapeAll = async () => {
    setScraping(true); setScrapeResults([])
    try {
      const r = await fetch('/api/specialist-desks/bank-forecasts/scrape', { method: 'POST' }).then(x => x.json())
      setScrapeResults(r.results ?? [])
      load()
    } finally { setScraping(false) }
  }

  const pushConsensus = async () => {
    setPushing(true)
    try {
      await fetch('/api/specialist-desks/bank-forecasts/push-consensus', { method: 'POST' })
    } finally { setPushing(false) }
  }

  // Group forecasts by (event_date, series_id) for display
  const grouped = forecasts.reduce<Record<string, BankForecast[]>>((acc, f) => {
    const key = `${f.event_date}|${f.series_id}`
    if (!acc[key]) acc[key] = []
    acc[key].push(f)
    return acc
  }, {})

  return (
    <div className="p-6 space-y-6">
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-lg font-bold text-slate-100 flex items-center gap-2">
            <Landmark className="w-5 h-5 text-amber-400" />
            Bank Forecasts
          </h1>
          <p className="text-xs text-slate-500 mt-0.5">Prévisions publiques scrappées — consensus maison</p>
        </div>
        <div className="flex gap-2">
          <button onClick={scrapeAll} disabled={scraping}
            className="flex items-center gap-1.5 text-xs bg-amber-900/30 hover:bg-amber-900/50 border border-amber-700/40 text-amber-300 px-3 py-2 rounded transition-colors disabled:opacity-50">
            <Play className="w-3.5 h-3.5" /> {scraping ? 'Scraping…' : 'Scrape all'}
          </button>
          <button onClick={pushConsensus} disabled={pushing}
            className="flex items-center gap-1.5 text-xs bg-emerald-900/30 hover:bg-emerald-900/50 border border-emerald-700/40 text-emerald-300 px-3 py-2 rounded transition-colors disabled:opacity-50">
            <Send className="w-3.5 h-3.5" /> {pushing ? '…' : '→ macro_series_log'}
          </button>
        </div>
      </div>

      {/* Sources config */}
      <div className="bg-dark-800 border border-slate-700/40 rounded-lg overflow-hidden">
        <div className="px-4 py-2.5 border-b border-slate-700/40 text-xs font-bold text-slate-400 uppercase tracking-wide">
          Sources ({sources.filter(s => s.active).length} actives)
        </div>
        <table className="w-full text-xs">
          <thead>
            <tr className="text-[10px] text-slate-500 border-b border-slate-700/30">
              <th className="text-left px-4 py-2">Banque</th>
              <th className="text-left px-4 py-2">URL</th>
              <th className="text-left px-4 py-2">Dernier scrape</th>
              <th className="px-4 py-2"></th>
            </tr>
          </thead>
          <tbody>
            {sources.map(src => (
              <tr key={src.id} className="border-b border-slate-700/20 hover:bg-dark-700/30">
                <td className="px-4 py-2 font-medium text-slate-200">{src.name}</td>
                <td className="px-4 py-2 max-w-xs">
                  {editId === src.id ? (
                    <input value={editUrl} onChange={e => setEditUrl(e.target.value)}
                      className="w-full bg-dark-700 border border-slate-600 rounded px-2 py-1 text-xs text-slate-200 font-mono"
                      placeholder="https://..." />
                  ) : (
                    <span className={clsx('font-mono truncate block', src.url ? 'text-cyan-400' : 'text-slate-700 italic')}>
                      {src.url || 'non configurée'}
                    </span>
                  )}
                </td>
                <td className="px-4 py-2 text-slate-600 tabular-nums">
                  {src.last_scraped ? src.last_scraped.slice(0, 16) : '—'}
                </td>
                <td className="px-4 py-2">
                  {editId === src.id ? (
                    <div className="flex gap-1">
                      <button onClick={() => saveSource(src)}
                        className="text-emerald-400 hover:text-emerald-200 px-2 py-0.5 border border-emerald-800/40 rounded text-[10px]">
                        Sauver
                      </button>
                      <button onClick={() => setEditId(null)}
                        className="text-slate-500 hover:text-slate-300 px-2 py-0.5 border border-slate-700/40 rounded text-[10px]">
                        Annuler
                      </button>
                    </div>
                  ) : (
                    <button onClick={() => { setEditId(src.id); setEditUrl(src.url); setEditNotes(src.notes) }}
                      className="text-slate-600 hover:text-slate-300 transition-colors">
                      <Edit2 className="w-3.5 h-3.5" />
                    </button>
                  )}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {/* Scrape results */}
      {scrapeResults.length > 0 && (
        <div className="bg-dark-800 border border-slate-700/40 rounded-lg p-4">
          <div className="text-xs font-bold text-slate-400 uppercase tracking-wide mb-2">Résultats scrape</div>
          <div className="space-y-1">
            {scrapeResults.map((r, i) => (
              <div key={i} className="flex gap-3 text-xs font-mono">
                <span className={clsx('w-32 truncate', r.fetched ? 'text-slate-300' : 'text-red-400')}>{r.name}</span>
                <span className="text-slate-500">fetched={r.fetched ? '✓' : '✗'}</span>
                <span className="text-emerald-500">saved={r.saved}</span>
                {r.error && <span className="text-red-400 truncate">{r.error}</span>}
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Consensus table */}
      {consensus.length > 0 && (
        <div className="bg-dark-800 border border-slate-700/40 rounded-lg overflow-hidden">
          <div className="px-4 py-2.5 border-b border-slate-700/40 text-xs font-bold text-slate-400 uppercase tracking-wide">
            Consensus maison ({consensus.length} events)
          </div>
          <table className="w-full text-xs">
            <thead>
              <tr className="text-[10px] text-slate-500 border-b border-slate-700/30">
                <th className="text-left px-4 py-2">Release</th>
                <th className="text-left px-4 py-2">Série</th>
                <th className="text-right px-4 py-2">Consensus</th>
                <th className="text-right px-4 py-2">Range</th>
                <th className="text-right px-4 py-2">Banques</th>
              </tr>
            </thead>
            <tbody>
              {consensus.map((c, i) => (
                <tr key={i} className="border-b border-slate-700/20 hover:bg-dark-700/30">
                  <td className="px-4 py-2 tabular-nums text-slate-400">{c.event_date}</td>
                  <td className="px-4 py-2 text-slate-200">{c.event_name || c.series_id}</td>
                  <td className="px-4 py-2 text-right font-mono font-bold text-amber-300">{c.consensus.toFixed(2)}</td>
                  <td className="px-4 py-2 text-right font-mono text-slate-500">
                    {c.min_forecast.toFixed(2)} – {c.max_forecast.toFixed(2)}
                  </td>
                  <td className="px-4 py-2 text-right text-slate-400">{c.bank_count}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {/* Detail by event */}
      {Object.entries(grouped).length > 0 && (
        <div className="space-y-3">
          <div className="text-xs font-bold text-slate-400 uppercase tracking-wide">Détail par événement</div>
          {Object.entries(grouped).sort(([a], [b]) => b.localeCompare(a)).map(([key, items]) => {
            const [date, series] = key.split('|')
            return (
              <div key={key} className="bg-dark-800 border border-slate-700/40 rounded-lg overflow-hidden">
                <div className="px-4 py-2 border-b border-slate-700/30 flex items-center gap-3">
                  <span className="text-xs font-mono text-slate-400">{date}</span>
                  <span className="text-xs font-bold text-slate-200">{items[0].event_name || series}</span>
                  <span className="text-[10px] text-slate-600">{series}</span>
                </div>
                <table className="w-full text-xs">
                  <tbody>
                    {items.map((f, i) => (
                      <tr key={i} className="border-b border-slate-800/60 last:border-0">
                        <td className="px-4 py-1.5 text-slate-400 w-36">{f.bank_name}</td>
                        <td className="px-4 py-1.5 font-mono font-bold text-amber-300">
                          {f.forecast_value != null ? f.forecast_value.toFixed(2) : '—'} {f.unit}
                        </td>
                        <td className={clsx('px-4 py-1.5 text-[10px]',
                          f.confidence === 'high' ? 'text-emerald-600' : f.confidence === 'low' ? 'text-red-700' : 'text-slate-600')}>
                          {f.confidence}
                        </td>
                        <td className="px-4 py-1.5 text-slate-600 italic max-w-xs truncate" title={f.snippet}>{f.snippet}</td>
                        <td className="px-4 py-1.5 text-slate-700 tabular-nums text-[10px]">{f.extracted_at.slice(0, 16)}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )
          })}
        </div>
      )}

      {Object.entries(grouped).length === 0 && consensus.length === 0 && !scraping && (
        <div className="text-center py-16 text-slate-600">
          <Landmark className="w-10 h-10 mx-auto mb-3 opacity-20" />
          <p className="text-sm">Aucune prévision bancaire</p>
          <p className="text-xs mt-1">Configurez les URLs des banques puis cliquez "Scrape all"</p>
        </div>
      )}
    </div>
  )
}

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

export default function SpecialistDesks() {
  const { data: desks = [], isLoading: desksLoading } = useAllDeskConfigs()
  const { data: allReports = [] } = useAllSpecialistReports()
  const { mutateAsync: updateDesk, isPending: savingDesk } = useUpdateDeskConfig()
  const { mutateAsync: createReport } = useCreateSpecialistReport()
  const { mutateAsync: updateReport } = useUpdateSpecialistReport()
  const { mutate: deleteReport } = useDeleteSpecialistReport()
  const { mutate: linkReport } = useLinkReportDesk()
  const { mutate: unlinkReport } = useUnlinkReportDesk()

  const { data: cotData = [], isLoading: cotLoading }         = useCotData()
  const { data: curveData = [], isLoading: curvesLoading }    = useForwardCurves()
  const { mutate: fetchCot,    isPending: fetchingCot }       = useFetchCot()
  const { mutate: fetchCurves, isPending: fetchingCurves }    = useFetchForwardCurves()
  const { mutateAsync: updateReportResult }                   = useUpdateReportResult()
  const { mutateAsync: scoreText, isPending: scoringText }    = useScoreText()
  const [scoreTextInput, setScoreTextInput]                   = useState('')
  const [scoreTextResult, setScoreTextResult]                 = useState<TextSentimentResult | null>(null)
  const [scoreReportName, setScoreReportName]                 = useState('')

  const orderedDesks = DESK_ORDER
    .map(ac => desks.find(d => d.asset_class === ac))
    .filter(Boolean) as DeskConfig[]

  const [activeDeskAc, setActiveDeskAc] = useState<string>(DESK_ORDER[0])
  const [activeTab,    setActiveTab]    = useState<'config' | 'reports' | 'all-reports' | 'cot' | 'curves' | 'bank-forecasts'>('config')

  // Desk edit state
  const [editFund,    setEditFund]    = useState('')
  const [editMacro,   setEditMacro]   = useState<MacroSensitivity[]>([])
  const [editThresh,  setEditThresh]  = useState({ significant_day: 1.0, extreme_day: 3.0, significant_week: 2.0, extreme_week: 5.0 })
  const [editNotes,   setEditNotes]   = useState('')
  const [dirty,       setDirty]       = useState(false)

  // Report modal
  const [reportModal, setReportModal] = useState<null | 'new' | (SpecialistReport & { desks?: string[] })>(null)

  const activeDesk = desks.find(d => d.asset_class === activeDeskAc)

  const selectDesk = (ac: string) => {
    const d = desks.find(x => x.asset_class === ac)
    if (!d) return
    setActiveDeskAc(ac)
    setEditFund(d.fundamentals)
    setEditMacro(d.macro_sensitivity ?? [])
    setEditThresh(d.price_delta_thresholds ?? { significant_day: 1, extreme_day: 3, significant_week: 2, extreme_week: 5 })
    setEditNotes(d.notes ?? '')
    setDirty(false)
    setActiveTab('config')
  }

  // Init on first load
  const [initialized, setInitialized] = useState(false)
  if (!initialized && desks.length > 0) {
    setInitialized(true)
    selectDesk(DESK_ORDER[0])
  }

  const handleSaveDesk = async () => {
    if (!activeDesk) return
    await updateDesk({
      asset_class: activeDeskAc,
      body: {
        display_name: activeDesk.display_name,
        icon: activeDesk.icon,
        fundamentals: editFund,
        macro_sensitivity: editMacro,
        price_delta_thresholds: editThresh,
        notes: editNotes,
      },
    })
    setDirty(false)
  }

  const handleCreateReport = async (data: any) => {
    await createReport(data)
    setReportModal(null)
  }

  const handleUpdateReport = async (data: any) => {
    if (!reportModal || reportModal === 'new') return
    await updateReport({ id: (reportModal as SpecialistReport).id, body: data })
    setReportModal(null)
  }

  const deskReports = activeDesk?.reports ?? []
  const today = new Date().toISOString().slice(0, 10)

  if (desksLoading) {
    return (
      <div className="flex items-center justify-center h-screen text-slate-500">
        <RefreshCw className="w-5 h-5 animate-spin mr-2" /> Loading desks…
      </div>
    )
  }

  return (
    <div className="flex h-screen bg-dark-900 text-slate-200 overflow-hidden">
      {/* ── Left: desk list ─────────────────────────────────────────────────── */}
      <div className="w-52 flex-shrink-0 border-r border-slate-700/40 flex flex-col">
        <div className="p-4 border-b border-slate-700/40">
          <div className="flex items-center gap-2">
            <Users className="w-4 h-4 text-violet-400" />
            <span className="font-semibold text-sm text-slate-100">Specialist Desks</span>
          </div>
          <p className="text-[10px] text-slate-600 mt-1">Per asset-class fundamental configs + reports</p>
        </div>

        <nav className="flex-1 py-2 overflow-y-auto">
          {orderedDesks.map(d => (
            <button
              key={d.asset_class}
              onClick={() => selectDesk(d.asset_class)}
              className={clsx(
                'w-full text-left px-4 py-3 flex items-center gap-3 border-b border-slate-700/20 transition-colors',
                d.asset_class === activeDeskAc
                  ? 'bg-violet-900/30 border-l-2 border-l-violet-500'
                  : 'hover:bg-dark-700/50'
              )}>
              <span className="text-lg">{d.icon}</span>
              <div>
                <div className="text-xs font-medium text-slate-200">{d.display_name}</div>
                <div className="text-[10px] text-slate-600">{d.reports.length} report{d.reports.length !== 1 ? 's' : ''}</div>
              </div>
            </button>
          ))}
        </nav>

        {/* All reports link */}
        <button
          onClick={() => setActiveTab('all-reports')}
          className={clsx(
            'px-4 py-3 flex items-center gap-2 border-t border-slate-700/40 transition-colors text-xs',
            activeTab === 'all-reports'
              ? 'bg-slate-700/50 text-slate-200'
              : 'text-slate-500 hover:text-slate-300'
          )}>
          <FileText className="w-3.5 h-3.5" />
          All Reports ({allReports.length})
        </button>
        <button
          onClick={() => setActiveTab('cot')}
          className={clsx(
            'px-4 py-3 flex items-center gap-2 border-t border-slate-700/40 transition-colors text-xs',
            activeTab === 'cot'
              ? 'bg-slate-700/50 text-slate-200'
              : 'text-slate-500 hover:text-slate-300'
          )}>
          <BarChart2 className="w-3.5 h-3.5" />
          COT Positioning
        </button>
        <button
          onClick={() => setActiveTab('curves')}
          className={clsx(
            'px-4 py-3 flex items-center gap-2 border-t border-slate-700/40 transition-colors text-xs',
            activeTab === 'curves'
              ? 'bg-slate-700/50 text-slate-200'
              : 'text-slate-500 hover:text-slate-300'
          )}>
          <Activity className="w-3.5 h-3.5" />
          Forward Curves
        </button>
        <button
          onClick={() => setActiveTab('bank-forecasts')}
          className={clsx(
            'px-4 py-3 flex items-center gap-2 border-t border-slate-700/40 transition-colors text-xs',
            activeTab === 'bank-forecasts'
              ? 'bg-amber-900/30 text-amber-300'
              : 'text-slate-500 hover:text-slate-300'
          )}>
          <Landmark className="w-3.5 h-3.5" />
          Bank Forecasts
        </button>
      </div>

      {/* ── Right: desk detail / all reports ──────────────────────────────── */}
      <div className="flex-1 overflow-y-auto">

        {/* ══ COT VIEW ════════════════════════════════════════════ */}
        {activeTab === 'cot' && (
          <div className="p-6 space-y-4">
            <div className="flex items-center justify-between">
              <div>
                <h1 className="text-lg font-bold text-slate-100 flex items-center gap-2">
                  <BarChart2 className="w-5 h-5 text-cyan-400" />
                  COT Positioning
                </h1>
                <p className="text-xs text-slate-500 mt-0.5">CFTC Commitment of Traders — Money Manager net positions (% of Open Interest)</p>
              </div>
              <button
                onClick={() => fetchCot()}
                disabled={fetchingCot}
                className="flex items-center gap-1.5 bg-cyan-800 hover:bg-cyan-700 disabled:opacity-40 text-white px-3 py-2 rounded text-xs font-semibold transition-colors">
                <RefreshCw className={clsx('w-3.5 h-3.5', fetchingCot && 'animate-spin')} />
                {fetchingCot ? 'Fetching…' : 'Refresh CFTC'}
              </button>
            </div>

            {cotLoading ? (
              <div className="text-slate-500 text-sm flex items-center gap-2">
                <RefreshCw className="w-4 h-4 animate-spin" /> Loading…
              </div>
            ) : cotData.length === 0 ? (
              <div className="text-slate-500 text-sm p-8 text-center border border-dashed border-slate-700 rounded-lg">
                No COT data yet. Click "Refresh CFTC" to fetch the latest weekly report.
              </div>
            ) : (
              <div className="space-y-4">
                {(['energy', 'metals', 'agri', 'forex', 'bonds'] as const).map(ac => {
                  const entries = cotData.filter(c => c.asset_class === ac)
                  if (!entries.length) return null
                  const labels: Record<string, string> = { energy: '⚡ Energy', metals: '🥇 Metals', agri: '🌾 Agri & Softs', forex: '💱 Forex', bonds: '📉 Bonds' }
                  const reportDate = entries[0]?.report_date
                  return (
                    <div key={ac} className="bg-dark-800 border border-slate-700/40 rounded-lg overflow-hidden">
                      <div className="flex items-center justify-between px-4 py-2.5 border-b border-slate-700/40 bg-dark-700/50">
                        <span className="text-xs font-bold text-slate-200">{labels[ac] || ac}</span>
                        {reportDate && <span className="text-[10px] text-slate-500 font-mono">COT week of {reportDate}</span>}
                      </div>
                      <div className="divide-y divide-slate-700/30">
                        {entries.map(entry => {
                          const pct = entry.net_pct_oi
                          const isLong = pct > 5
                          const isShort = pct < -5
                          const barWidth = Math.min(Math.abs(pct), 50)  // cap at 50%
                          const chg = entry.change_net
                          return (
                            <div key={entry.id} className="px-4 py-3 flex items-center gap-4">
                              <div className="w-28 flex-shrink-0 text-xs font-medium text-slate-200">{entry.commodity}</div>
                              {/* Net position bar */}
                              <div className="flex-1 flex items-center gap-2">
                                <div className="w-24 h-2 bg-slate-700/50 rounded-full overflow-hidden relative">
                                  <div className="absolute inset-0 flex items-center justify-center">
                                    <div className="w-px h-full bg-slate-600" />
                                  </div>
                                  {pct > 0 ? (
                                    <div className="absolute left-1/2 top-0 h-full bg-emerald-500 rounded-r"
                                      style={{ width: `${barWidth}%` }} />
                                  ) : (
                                    <div className="absolute right-1/2 top-0 h-full bg-red-500 rounded-l"
                                      style={{ width: `${barWidth}%` }} />
                                  )}
                                </div>
                                <span className={clsx(
                                  'text-xs font-mono font-bold min-w-[50px]',
                                  isLong ? 'text-emerald-400' : isShort ? 'text-red-400' : 'text-slate-400'
                                )}>
                                  {pct >= 0 ? '+' : ''}{pct.toFixed(1)}%
                                </span>
                                <span className={clsx('text-[10px] px-1.5 py-0.5 rounded font-bold',
                                  isLong ? 'bg-emerald-900/50 text-emerald-300' : isShort ? 'bg-red-900/50 text-red-300' : 'bg-slate-700/50 text-slate-400'
                                )}>
                                  {isLong ? 'LONG' : isShort ? 'SHORT' : 'NEUTRAL'}
                                </span>
                              </div>
                              {/* Weekly change */}
                              {chg !== 0 && (
                                <div className={clsx('flex items-center gap-0.5 text-[10px] font-mono',
                                  chg > 0 ? 'text-emerald-400' : 'text-red-400')}>
                                  {chg > 0 ? <ArrowUp className="w-2.5 h-2.5" /> : <ArrowDown className="w-2.5 h-2.5" />}
                                  {Math.abs(chg).toLocaleString()}
                                </div>
                              )}
                              {/* Net position (contracts) */}
                              <div className="text-[10px] font-mono text-slate-500 text-right w-28">
                                {entry.net_position.toLocaleString()} net
                              </div>
                            </div>
                          )
                        })}
                      </div>
                    </div>
                  )
                })}
                <p className="text-[10px] text-slate-600 text-center">
                  Source: CFTC Disaggregated Futures (commodities) + Legacy Financial (forex/bonds) — published weekly on Fridays
                </p>
              </div>
            )}
          </div>
        )}

        {/* ══ FORWARD CURVES VIEW ══════════════════════════════════ */}
        {activeTab === 'curves' && (
          <div className="p-6 space-y-4">
            <div className="flex items-center justify-between">
              <div>
                <h1 className="text-lg font-bold text-slate-100 flex items-center gap-2">
                  <Activity className="w-5 h-5 text-amber-400" />
                  Forward Curves
                </h1>
                <p className="text-xs text-slate-500 mt-0.5">Contango / Backwardation — spot vs +3M futures slope (yfinance)</p>
              </div>
              <button
                onClick={() => fetchCurves()}
                disabled={fetchingCurves}
                className="flex items-center gap-1.5 bg-amber-800 hover:bg-amber-700 disabled:opacity-40 text-white px-3 py-2 rounded text-xs font-semibold transition-colors">
                <RefreshCw className={clsx('w-3.5 h-3.5', fetchingCurves && 'animate-spin')} />
                {fetchingCurves ? 'Fetching…' : 'Refresh Curves'}
              </button>
            </div>

            {curvesLoading ? (
              <div className="text-slate-500 text-sm flex items-center gap-2">
                <RefreshCw className="w-4 h-4 animate-spin" /> Loading…
              </div>
            ) : curveData.length === 0 ? (
              <div className="text-slate-500 text-sm p-8 text-center border border-dashed border-slate-700 rounded-lg">
                No forward curve data yet. Click "Refresh Curves" to fetch.
              </div>
            ) : (
              <div className="space-y-4">
                {(['energy', 'metals', 'agri'] as const).map(ac => {
                  const entries = curveData.filter(c => c.asset_class === ac)
                  if (!entries.length) return null
                  const labels: Record<string, string> = { energy: '⚡ Energy', metals: '🥇 Metals', agri: '🌾 Agri & Softs' }
                  return (
                    <div key={ac} className="bg-dark-800 border border-slate-700/40 rounded-lg overflow-hidden">
                      <div className="px-4 py-2.5 border-b border-slate-700/40 bg-dark-700/50">
                        <span className="text-xs font-bold text-slate-200">{labels[ac]}</span>
                      </div>
                      <div className="grid grid-cols-2 gap-0 divide-y divide-slate-700/30">
                        {entries.map(e => {
                          const isContango = e.structure === 'contango'
                          const isBackward = e.structure === 'backwardation'
                          const slope = e.slope_pct
                          return (
                            <div key={e.id} className="px-4 py-3 flex items-center gap-3 border-r border-slate-700/30 last:border-r-0">
                              <div className="flex-1">
                                <div className="text-xs font-medium text-slate-200">{e.asset}</div>
                                <div className="text-[10px] text-slate-500 font-mono mt-0.5">
                                  Front: {e.front_price?.toFixed(2) ?? '—'}
                                  {e.far_price && ` | +3M: ${e.far_price.toFixed(2)}`}
                                </div>
                              </div>
                              <div className="text-right flex-shrink-0">
                                <div className={clsx('flex items-center gap-1 text-xs font-bold',
                                  isContango ? 'text-sky-400' : isBackward ? 'text-orange-400' : 'text-slate-400'
                                )}>
                                  {isContango ? <TrendingUp className="w-3 h-3" />
                                    : isBackward ? <TrendingDown className="w-3 h-3" />
                                    : <Minus className="w-3 h-3" />}
                                  {e.structure.toUpperCase()}
                                </div>
                                {slope !== null && (
                                  <div className={clsx('text-[10px] font-mono mt-0.5',
                                    slope > 0 ? 'text-sky-500' : slope < 0 ? 'text-orange-500' : 'text-slate-500'
                                  )}>
                                    {slope >= 0 ? '+' : ''}{slope.toFixed(2)}%
                                  </div>
                                )}
                              </div>
                            </div>
                          )
                        })}
                      </div>
                    </div>
                  )
                })}
                <div className="bg-dark-800 border border-slate-700/40 rounded-lg p-4">
                  <div className="text-[10px] text-slate-500 space-y-1">
                    <div><span className="text-sky-400 font-bold">CONTANGO</span> = futures prix &gt; spot → marché normal (coût de stockage) → <em>pénalise les positions longues au rollover</em></div>
                    <div><span className="text-orange-400 font-bold">BACKWARDATION</span> = futures prix &lt; spot → pénurie physique immédiate → <em>profite aux positions longues au rollover</em></div>
                  </div>
                </div>
              </div>
            )}
          </div>
        )}

        {activeTab === 'all-reports' ? (
          /* ══ ALL REPORTS VIEW ════════════════════════════════════════════ */
          <div className="p-6 space-y-4">
            <div className="flex items-center justify-between">
              <div>
                <h1 className="text-lg font-bold text-slate-100 flex items-center gap-2">
                  <FileText className="w-5 h-5 text-violet-400" />
                  Report Catalogue
                </h1>
                <p className="text-xs text-slate-500 mt-0.5">All reports — manual and auto-tracked</p>
              </div>
              <button
                onClick={() => setReportModal('new')}
                className="flex items-center gap-1.5 bg-violet-700 hover:bg-violet-600 text-white px-3 py-2 rounded text-xs font-semibold transition-colors">
                <Plus className="w-3.5 h-3.5" /> New Report
              </button>
            </div>

            <div className="bg-dark-800 border border-slate-700/40 rounded-lg overflow-hidden">
              <table className="w-full text-xs">
                <thead>
                  <tr className="text-[10px] text-slate-500 uppercase tracking-wide border-b border-slate-700/40">
                    <th className="text-left px-4 py-2">Report</th>
                    <th className="text-left px-3 py-2">Source</th>
                    <th className="text-left px-3 py-2">Cadence</th>
                    <th className="text-left px-3 py-2">Next date</th>
                    <th className="text-left px-3 py-2">Desks</th>
                    <th className="text-left px-3 py-2">Imp.</th>
                    <th className="px-3 py-2"></th>
                  </tr>
                </thead>
                <tbody>
                  {allReports.map(r => (
                    <tr key={r.id} className="border-b border-slate-700/20 hover:bg-dark-700/40 transition-colors">
                      <td className="px-4 py-2">
                        <div className="font-medium text-slate-200">{r.name}</div>
                        {r.notes && <div className="text-[10px] text-slate-600 truncate max-w-[200px]">{r.notes}</div>}
                      </td>
                      <td className="px-3 py-2 text-slate-400">{r.source}</td>
                      <td className="px-3 py-2">
                        <span className="bg-dark-700 rounded px-1.5 py-0.5 text-slate-400 font-mono">{r.cadence}</span>
                      </td>
                      <td className="px-3 py-2">
                        {r.next_date ? (
                          <span className={clsx(
                            'font-mono',
                            r.next_date <= today ? 'text-orange-400' : 'text-slate-300'
                          )}>{r.next_date}</span>
                        ) : <span className="text-slate-700">—</span>}
                      </td>
                      <td className="px-3 py-2">
                        <div className="flex flex-wrap gap-1">
                          {(r.desks ?? []).map(ac => {
                            const d = desks.find(x => x.asset_class === ac)
                            return d ? (
                              <span key={ac} className="text-[10px] bg-dark-700 rounded px-1 text-slate-400">
                                {d.icon}
                              </span>
                            ) : null
                          })}
                        </div>
                      </td>
                      <td className="px-3 py-2"><Stars n={r.importance} /></td>
                      <td className="px-3 py-2">
                        <div className="flex items-center gap-1">
                          {r.url && (
                            <a href={r.url} target="_blank" rel="noopener noreferrer"
                              className="text-slate-600 hover:text-violet-400 transition-colors">
                              <ExternalLink className="w-3 h-3" />
                            </a>
                          )}
                          <button onClick={() => setReportModal(r as any)}
                            className="text-slate-600 hover:text-slate-300 transition-colors">
                            <Edit2 className="w-3 h-3" />
                          </button>
                          <button onClick={() => deleteReport(r.id)}
                            className="text-slate-600 hover:text-red-400 transition-colors">
                            <Trash2 className="w-3 h-3" />
                          </button>
                        </div>
                      </td>
                    </tr>
                  ))}
                  {allReports.length === 0 && (
                    <tr><td colSpan={7} className="px-4 py-8 text-center text-slate-600">No reports yet</td></tr>
                  )}
                </tbody>
              </table>
            </div>
          </div>
        ) : activeDesk ? (
          /* ══ DESK DETAIL ═════════════════════════════════════════════════ */
          <div className="p-6 space-y-5">
            {/* Header */}
            <div className="flex items-start justify-between">
              <div>
                <h1 className="text-xl font-bold text-slate-100 flex items-center gap-2">
                  <span className="text-2xl">{activeDesk.icon}</span>
                  {activeDesk.display_name}
                  <span className="text-[10px] text-slate-500 uppercase tracking-widest font-normal ml-1">Specialist Desk</span>
                </h1>
              </div>
              {dirty && (
                <button onClick={handleSaveDesk} disabled={savingDesk}
                  className="flex items-center gap-1.5 bg-emerald-700 hover:bg-emerald-600 disabled:opacity-50 text-white px-4 py-2 rounded text-xs font-semibold transition-colors">
                  {savingDesk ? <RefreshCw className="w-3.5 h-3.5 animate-spin" /> : <Save className="w-3.5 h-3.5" />}
                  Save changes
                </button>
              )}
            </div>

            {/* Tabs */}
            <div className="flex gap-1 bg-dark-800 rounded p-0.5 w-fit">
              {(['config', 'reports'] as const).map(tab => (
                <button key={tab} onClick={() => setActiveTab(tab)}
                  className={clsx('px-4 py-1.5 text-xs rounded transition-colors font-medium flex items-center gap-1.5', {
                    'bg-violet-700 text-white': activeTab === tab,
                    'text-slate-500 hover:text-slate-300': activeTab !== tab,
                  })}>
                  {tab === 'config' ? <BookOpen className="w-3 h-3" /> : <FileText className="w-3 h-3" />}
                  {tab === 'config' ? 'Fundamentals' : `Reports (${deskReports.length})`}
                </button>
              ))}
            </div>

            {/* ── CONFIG TAB ── */}
            {activeTab === 'config' && (
              <div className="space-y-5">
                {/* Key drivers */}
                <div className="bg-dark-800 border border-slate-700/40 rounded-lg p-4">
                  <label className="text-xs font-semibold text-slate-400 uppercase tracking-wide mb-2 block">
                    Key Fundamental Drivers
                  </label>
                  <textarea
                    value={editFund}
                    onChange={e => { setEditFund(e.target.value); setDirty(true) }}
                    rows={4}
                    placeholder="Describe the primary price drivers for this asset class…"
                    className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-300 focus:outline-none focus:border-violet-500 resize-none leading-relaxed"
                  />
                  <p className="text-[10px] text-slate-600 mt-1">This block is injected into the AI scorer prompt for relevant patterns.</p>
                </div>

                {/* Macro sensitivity */}
                <div className="bg-dark-800 border border-slate-700/40 rounded-lg p-4">
                  <label className="text-xs font-semibold text-slate-400 uppercase tracking-wide mb-2 block">
                    Macro Regime Sensitivity
                  </label>
                  <MacroSensitivityEditor
                    items={editMacro}
                    onChange={v => { setEditMacro(v); setDirty(true) }}
                  />
                  <p className="text-[10px] text-slate-600 mt-2">Format: regime identifier → market effect. Injected as signal context for the scorer.</p>
                </div>

                {/* Price thresholds */}
                <div className="bg-dark-800 border border-slate-700/40 rounded-lg p-4">
                  <label className="text-xs font-semibold text-slate-400 uppercase tracking-wide mb-3 block">
                    Price Move Thresholds
                  </label>
                  <div className="grid grid-cols-2 gap-4">
                    {([
                      ['significant_day',   'Significant (daily)'],
                      ['extreme_day',        'Extreme (daily)'],
                      ['significant_week',  'Significant (weekly)'],
                      ['extreme_week',       'Extreme (weekly)'],
                    ] as const).map(([key, label]) => (
                      <div key={key}>
                        <label className="text-[10px] text-slate-500 mb-1 block">{label}</label>
                        <div className="flex items-center gap-2">
                          <input
                            type="number" step="0.1" min="0"
                            value={editThresh[key]}
                            onChange={e => { setEditThresh(t => ({ ...t, [key]: parseFloat(e.target.value) || 0 })); setDirty(true) }}
                            className="w-20 px-2 py-1.5 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-200 focus:outline-none focus:border-violet-500 font-mono"
                          />
                          <span className="text-xs text-slate-500">%</span>
                        </div>
                      </div>
                    ))}
                  </div>
                </div>

                {/* Notes */}
                <div className="bg-dark-800 border border-slate-700/40 rounded-lg p-4">
                  <label className="text-xs font-semibold text-slate-400 uppercase tracking-wide mb-2 block">Notes</label>
                  <textarea
                    value={editNotes}
                    onChange={e => { setEditNotes(e.target.value); setDirty(true) }}
                    rows={2}
                    placeholder="Additional desk-specific notes…"
                    className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-300 focus:outline-none focus:border-violet-500 resize-none"
                  />
                </div>

                {/* ── Hawk/Dove Text Scorer (Forex & Bonds desks only) ── */}
                {(activeDeskAc === 'forex' || activeDeskAc === 'bonds') && (
                  <div className="mt-6 border-t border-slate-700/40 pt-5">
                    <div className="flex items-center gap-2 mb-3">
                      <FlaskConical className="w-4 h-4 text-violet-400" />
                      <span className="text-sm font-semibold text-slate-200">Hawk/Dove Text Scorer</span>
                      <span className="text-[10px] text-slate-500">— Paste a central bank statement to get an IA sentiment score</span>
                    </div>
                    <div className="space-y-3">
                      <input
                        value={scoreReportName}
                        onChange={e => setScoreReportName(e.target.value)}
                        placeholder="Report name (e.g. FOMC Minutes June 2026)"
                        className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-200 focus:outline-none focus:border-violet-500"
                      />
                      <textarea
                        value={scoreTextInput}
                        onChange={e => setScoreTextInput(e.target.value)}
                        rows={5}
                        placeholder="Paste the FOMC minutes, ECB statement, BoJ press release… (up to 3000 chars used)"
                        className="w-full px-3 py-2 text-xs bg-dark-700 border border-slate-600/50 rounded text-slate-300 focus:outline-none focus:border-violet-500 resize-none font-mono"
                      />
                      <div className="flex items-center gap-2">
                        <button
                          onClick={async () => {
                            if (!scoreTextInput.trim()) return
                            const result = await scoreText({ text: scoreTextInput, report_name: scoreReportName, desk: activeDeskAc })
                            setScoreTextResult(result)
                          }}
                          disabled={scoringText || !scoreTextInput.trim()}
                          className="flex items-center gap-1.5 px-4 py-2 bg-violet-700 hover:bg-violet-600 disabled:opacity-40 text-white text-xs font-semibold rounded transition-colors">
                          <FlaskConical className="w-3.5 h-3.5" />
                          {scoringText ? 'Analyzing…' : 'Score Text'}
                        </button>
                        {scoreTextResult && (
                          <button onClick={() => { setScoreTextResult(null); setScoreTextInput(''); setScoreReportName('') }}
                            className="text-xs text-slate-500 hover:text-slate-300 transition-colors">Clear</button>
                        )}
                      </div>
                      {scoreTextResult && (
                        <div className={clsx('rounded-lg border p-4 space-y-3',
                          scoreTextResult.score > 0.3 ? 'border-red-700/40 bg-red-900/10' :
                          scoreTextResult.score < -0.3 ? 'border-sky-700/40 bg-sky-900/10' :
                          'border-slate-700/40 bg-dark-700/30'
                        )}>
                          <div className="flex items-center justify-between">
                            <div className="flex items-center gap-2">
                              <span className={clsx('text-sm font-bold px-2 py-0.5 rounded',
                                scoreTextResult.score > 0.3 ? 'bg-red-800/50 text-red-200' :
                                scoreTextResult.score < -0.3 ? 'bg-sky-800/50 text-sky-200' :
                                'bg-slate-700/50 text-slate-300'
                              )}>
                                {scoreTextResult.label.replace(/_/g, ' ').toUpperCase()}
                              </span>
                              <span className="text-[10px] text-slate-500">confidence: {scoreTextResult.confidence}</span>
                            </div>
                            <div className="text-right">
                              <div className="text-lg font-mono font-bold" style={{
                                color: scoreTextResult.score > 0 ? '#f87171' : scoreTextResult.score < 0 ? '#38bdf8' : '#94a3b8'
                              }}>
                                {scoreTextResult.score >= 0 ? '+' : ''}{scoreTextResult.score.toFixed(2)}
                              </div>
                              <div className="text-[10px] text-slate-500">score (−1=dovish, +1=hawkish)</div>
                            </div>
                          </div>
                          <p className="text-xs text-slate-300 leading-relaxed">{scoreTextResult.summary}</p>
                          {scoreTextResult.key_phrases?.length > 0 && (
                            <div className="flex flex-wrap gap-1.5">
                              {scoreTextResult.key_phrases.map((phrase, i) => (
                                <span key={i} className="px-2 py-0.5 bg-slate-700/50 border border-slate-600/40 rounded text-[10px] text-slate-400 italic">
                                  "{phrase}"
                                </span>
                              ))}
                            </div>
                          )}
                        </div>
                      )}
                    </div>
                  </div>
                )}
              </div>
            )}

            {/* ── REPORTS TAB ── */}
            {activeTab === 'reports' && (
              <div className="space-y-3">
                <div className="flex justify-between items-center">
                  <p className="text-xs text-slate-500">
                    Reports assigned to the <span className="text-violet-300">{activeDesk.display_name}</span> desk.
                    They appear in the AI scorer's specialist context when relevant patterns are scored.
                  </p>
                  <button
                    onClick={() => setReportModal('new')}
                    className="flex items-center gap-1.5 bg-violet-700 hover:bg-violet-600 text-white px-3 py-1.5 rounded text-xs font-semibold transition-colors">
                    <Plus className="w-3 h-3" /> New report
                  </button>
                </div>

                <div className="space-y-2">
                  {deskReports.map(r => {
                    const overdue = r.next_date && r.next_date <= today
                    return (
                      <div key={r.id}
                        className={clsx(
                          'flex items-center gap-3 px-4 py-3 rounded-lg border transition-colors',
                          overdue ? 'border-orange-700/40 bg-orange-900/10' : 'border-slate-700/40 bg-dark-800'
                        )}>
                        <div className="flex-1">
                          <div className="flex items-center gap-2 mb-0.5">
                            <span className="text-xs font-semibold text-slate-100">{r.name}</span>
                            {overdue && (
                              <span className="flex items-center gap-1 text-[10px] text-orange-400">
                                <AlertCircle className="w-3 h-3" /> Due
                              </span>
                            )}
                          </div>
                          <div className="flex items-center gap-3 text-[10px] text-slate-500">
                            <span>{r.source}</span>
                            <span className="bg-dark-700 rounded px-1 font-mono">{r.cadence}</span>
                            {r.next_date && (
                              <span className="flex items-center gap-1">
                                <Calendar className="w-3 h-3" />
                                Next: <span className={clsx('font-mono ml-0.5', overdue ? 'text-orange-400' : 'text-slate-300')}>{r.next_date}</span>
                              </span>
                            )}
                          </div>
                          {r.notes && <p className="text-[10px] text-slate-600 mt-0.5 italic">{r.notes}</p>}
                          <SurpriseInput
                            report={r}
                            onSave={(data) => updateReportResult({ id: r.id, body: data })}
                          />
                        </div>
                        <Stars n={r.importance} />
                        <div className="flex items-center gap-1.5">
                          {r.url && (
                            <a href={r.url} target="_blank" rel="noopener noreferrer"
                              className="text-slate-600 hover:text-violet-400 transition-colors">
                              <ExternalLink className="w-3.5 h-3.5" />
                            </a>
                          )}
                          <button onClick={() => setReportModal(r as any)}
                            className="text-slate-600 hover:text-slate-300 transition-colors">
                            <Edit2 className="w-3.5 h-3.5" />
                          </button>
                          <button
                            onClick={() => unlinkReport({ report_id: r.id, asset_class: activeDeskAc })}
                            title="Remove from this desk"
                            className="text-slate-600 hover:text-red-400 transition-colors">
                            <Link className="w-3.5 h-3.5" />
                          </button>
                        </div>
                      </div>
                    )
                  })}

                  {deskReports.length === 0 && (
                    <div className="text-center py-12 text-slate-600">
                      <FileText className="w-8 h-8 mx-auto mb-2 opacity-30" />
                      <p className="text-sm">No reports assigned to this desk</p>
                      <p className="text-xs mt-1">Create one with "New report" or assign existing ones from the global catalogue</p>
                    </div>
                  )}
                </div>

                {/* Unassigned reports that could be linked */}
                {(() => {
                  const unlinked = allReports.filter(
                    r => !(r.desks ?? []).includes(activeDeskAc)
                  )
                  if (unlinked.length === 0) return null
                  return (
                    <div className="border-t border-slate-700/30 pt-3">
                      <p className="text-[10px] text-slate-600 uppercase tracking-wide mb-2">Add existing report to this desk</p>
                      <div className="flex flex-wrap gap-2">
                        {unlinked.map(r => (
                          <button
                            key={r.id}
                            onClick={() => linkReport({ report_id: r.id, asset_class: activeDeskAc })}
                            className="flex items-center gap-1 px-2.5 py-1 text-xs border border-dashed border-slate-700 text-slate-500 hover:border-violet-600 hover:text-violet-300 rounded transition-colors">
                            <Plus className="w-3 h-3" /> {r.name}
                          </button>
                        ))}
                      </div>
                    </div>
                  )
                })()}
              </div>
            )}
          </div>
        ) : null}
      </div>

        {/* ══ BANK FORECASTS VIEW ════════════════════════════════════════════ */}
        {activeTab === 'bank-forecasts' && <BankForecastsPanel />}

      {/* ── Report modal ─────────────────────────────────────────────────────── */}
      {reportModal && (
        <ReportModal
          initial={reportModal === 'new' ? undefined : reportModal}
          allDesks={desks}
          onSave={reportModal === 'new' ? handleCreateReport : handleUpdateReport}
          onClose={() => setReportModal(null)}
        />
      )}
    </div>
  )
}
