"use client";

import { useEffect, useState, useCallback } from "react";
import { TrendingUp, TrendingDown, Minus, ChevronDown, ChevronUp, Loader2, Database } from "lucide-react";
import { CURRENCY_META, COUNTRY_PROFILES } from "@/lib/constants";
import { biasLabel, biasColor, calcMacroScore } from "@/lib/scoring";
import { saveCache, loadCache, formatCacheDate } from "@/lib/localCache";
import type { Currency, BiasPhase, RateExpectation } from "@/lib/types";
import type { CBRatePath } from "@/lib/rateprobability";
import type { SentimentEntry, CotEntry } from "@/lib/types";
import NarrativeButton from "./NarrativeButton";

interface Ind { value: number | null; prev: number | null; surprise: number | null; trend: "up"|"down"|"flat"|null; lastUpdated: string | null }
interface MacroForecasts {
  cpi: number | null; cpiSurprise: number | null;
  cpiCore: number | null;
  cpiMoM:  number | null;
  unemployment: number | null; unemploymentSurprise: number | null;
  pmiMfg: number | null; pmiMfgSurprise: number | null;
  pmiSvc: number | null; pmiSvcSurprise: number | null;
  pmiComposite: number | null; pmiCompositeSurprise: number | null;
  retailSales: number | null; retailSalesSurprise: number | null;
  gdp: number | null; gdpSurprise: number | null;
  employment: number | null; employmentSurprise: number | null;
}
interface MacroData { currency: string; indicators: Record<string, Ind | null>; forecasts?: MacroForecasts | null; fetchedAt: string }

interface Props {
  currency: Currency;
  expectations: Record<string, unknown> | null;
  yields: { yields: Record<string, number | null>; spreads: Record<string, number | null> } | null;
  sentiment: SentimentEntry | null;
  cot: CotEntry | null;
  ratePath: CBRatePath | null;
  onDivergenceUpdate: (currency: Currency, score: number) => void;
}

const PHASES: Record<BiasPhase, { label: string; color: string }> = {
  tightening:    { label: "🔴 Resserrement",  color: "text-red-600"    },
  hawkish_pause: { label: "🟡 Pause Hawkish", color: "text-amber-600"  },
  easing:        { label: "🟢 Assouplissement", color: "text-green-600" },
  dovish_pause:  { label: "🔵 Pause Dovish",  color: "text-blue-600"   },
  transition:    { label: "🟠 Transition",     color: "text-orange-500" },
};

function SectionHeader({ label }: { label: string }) {
  return (
    <div className="flex items-center gap-1.5 pt-1.5 pb-0.5">
      <span className="text-[8px] font-bold text-gray-300 uppercase tracking-widest whitespace-nowrap">{label}</span>
      <div className="flex-1 h-px bg-gray-100" />
    </div>
  );
}

function TrendIcon({ trend }: { trend: "up"|"down"|"flat"|null }) {
  if (trend === "up")   return <TrendingUp  size={11} className="text-green-500 flex-shrink-0" />;
  if (trend === "down") return <TrendingDown size={11} className="text-red-500   flex-shrink-0" />;
  return <Minus size={11} className="text-gray-300 flex-shrink-0" />;
}

function Row({ label, ind, unit = "", invertSurprise = false, warn = false, consensus = null, surpriseVsCons = null, tooltip = null }: {
  label: string; ind: Ind | null; unit?: string; invertSurprise?: boolean; warn?: boolean;
  consensus?: number | null;
  surpriseVsCons?: number | null;
  tooltip?: string | null;
}) {
  const value = ind?.value ?? null;
  const prev  = ind?.prev  ?? null;

  // Colorer la valeur actuelle selon la direction du mouvement vs période précédente
  const s = ind?.surprise ?? null;
  const effectiveS = invertSurprise && s !== null ? -s : s;
  const valCls =
    effectiveS === null ? "text-gray-800"
    : effectiveS > 0   ? "text-green-700"
    : effectiveS < 0   ? "text-red-700"
    :                    "text-gray-500";

  const fmt = (v: number | null) =>
    v !== null ? `${v.toFixed(2)}${unit}` : "—";

  // Coloration de la surprise vs consensus (inversion pour chômage/unemployment)
  const effSurprise = invertSurprise && surpriseVsCons !== null ? -surpriseVsCons : surpriseVsCons;
  const surpriseCls = effSurprise === null ? ""
    : effSurprise > 0 ? "text-green-600"
    : effSurprise < 0 ? "text-red-600"
    : "text-gray-500";
  const surpriseArrow = effSurprise === null ? "" : effSurprise > 0 ? "▲" : effSurprise < 0 ? "▼" : "▬";

  return (
    <div className="py-1.5 border-b border-gray-50 last:border-0">
      {/* Ligne 1 : label + valeur actuelle publiée */}
      <div className="flex items-center justify-between gap-2">
        <div className="flex items-center gap-1.5 min-w-0">
          <TrendIcon trend={ind?.trend ?? null} />
          <span className="text-xs text-gray-500 truncate">
            {label}{warn && <span className="text-amber-400 ml-0.5">⚠</span>}
          </span>
        </div>
        <span className={`text-xs font-semibold tabular-nums flex-shrink-0 ${valCls}`} title={tooltip ?? undefined}>
          {fmt(value)}
        </span>
      </div>
      {/* Ligne 2 : précédent + consensus à venir OU surprise post-publication */}
      <div className="flex items-center justify-between pl-5 mt-0.5">
        <span className="text-[10px] text-gray-400 tabular-nums">
          Préc.&nbsp;<span className="text-gray-500 font-medium">{fmt(prev)}</span>
        </span>
        {surpriseVsCons !== null ? (
          // Surprise vs consensus (≤5 jours post-release)
          <span className="text-[10px] tabular-nums">
            <span className="text-gray-400">Surpr.&nbsp;</span>
            <span className={`font-medium ${surpriseCls}`}>
              {surpriseArrow}{surpriseVsCons > 0 ? "+" : ""}{surpriseVsCons.toFixed(2)}{unit}
            </span>
          </span>
        ) : (
          // Consensus à venir (upcoming)
          <span className="text-[10px] text-gray-400 tabular-nums">
            Cons.&nbsp;
            {consensus !== null
              ? <span className="text-blue-500 font-medium">{fmt(consensus)}</span>
              : <span className="text-gray-300">—</span>}
          </span>
        )}
      </div>
    </div>
  );
}

export default function CurrencyCard({ currency, expectations, yields, sentiment, cot, ratePath, onDivergenceUpdate }: Props) {
  const meta   = CURRENCY_META[currency];
  const [data, setData]         = useState<MacroData | null>(null);
  const [phase, setPhase]       = useState<BiasPhase>("hawkish_pause");
  const [loading, setLoading]   = useState(true);
  const [expanded, setExpanded] = useState(false);
  const [rateExp, setRateExp]   = useState<RateExpectation | null>(null);
  const [fromCache, setFromCache] = useState(false);
  const [cacheAge, setCacheAge]   = useState<string | null>(null);

  // Single fetch — server batches all FRED calls
  const load = useCallback(async () => {
    setLoading(true);
    const cacheKey = `macro_${currency}`;
    try {
      const res = await fetch(`/api/macro?currency=${currency}`);
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const json: MacroData = await res.json();
      if ("error" in json) throw new Error(String((json as Record<string,unknown>).error));

      // PMI est scraped mensuellement → si le serveur renvoie null cette semaine
      // (PMI pas encore publié), on conserve la valeur précédente du cache local.
      const prevCache = loadCache<MacroData>(cacheKey);
      const merged: MacroData = {
        ...json,
        indicators: {
          ...json.indicators,
          pmiMfg:      json.indicators.pmiMfg      ?? prevCache?.data.indicators.pmiMfg      ?? null,
          pmiServices: json.indicators.pmiServices ?? prevCache?.data.indicators.pmiServices ?? null,
        },
      };
      setData(merged);
      setFromCache(false);
      setCacheAge(null);
      saveCache(cacheKey, merged);

      // Infer phase from policy rate trend
      const rateInd = merged.indicators.policyRate;
      if (rateInd?.trend === "up")        setPhase("tightening");
      else if (rateInd?.trend === "down") setPhase("easing");
      else                                setPhase("hawkish_pause");
    } catch {
      // API indisponible → on utilise le cache localStorage si disponible
      const cached = loadCache<MacroData>(cacheKey);
      if (cached) {
        setData(cached.data);
        setFromCache(true);
        setCacheAge(formatCacheDate(cached.savedAt));
        const rateInd = cached.data.indicators.policyRate;
        if (rateInd?.trend === "up")        setPhase("tightening");
        else if (rateInd?.trend === "down") setPhase("easing");
        else                                setPhase("hawkish_pause");
      }
    } finally {
      setLoading(false);
    }
  }, [currency]);

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

  // Match rate expectation for this currency
  useEffect(() => {
    if (!expectations) return;
    const all = [
      ...((expectations.rate_hikes ?? []) as RateExpectation[]),
      ...((expectations.rate_cuts  ?? []) as RateExpectation[]),
    ];
    const cbShort = meta.cbShort.toLowerCase();
    setRateExp(all.find((e) => e.cb.toLowerCase().includes(cbShort) || e.cb.toLowerCase().includes(currency.toLowerCase())) ?? null);
  }, [expectations, currency, meta.cbShort]);

  const inds         = data?.indicators;
  const fc           = data?.forecasts ?? null;  // ForexFactory forecasts

  // Build a minimal indicator object for scoring
  const forScoring = {
    policyRate:   { value: inds?.policyRate?.value ?? null,   prev: inds?.policyRate?.prev ?? null,   consensus: null, surprise: inds?.policyRate?.surprise ?? null,   trend: inds?.policyRate?.trend ?? null,   lastUpdated: "" },
    cpiCore:      { value: inds?.cpiCore?.value ?? null,      prev: inds?.cpiCore?.prev ?? null,      consensus: null, surprise: inds?.cpiCore?.surprise ?? null,      trend: inds?.cpiCore?.trend ?? null,      lastUpdated: "" },
    pmiMfg:       { value: inds?.pmiMfg?.value      ?? null, prev: inds?.pmiMfg?.prev      ?? null, consensus: null, surprise: inds?.pmiMfg?.surprise      ?? null, trend: inds?.pmiMfg?.trend      ?? null, lastUpdated: "" },
    pmiServices:  { value: inds?.pmiServices?.value ?? null, prev: inds?.pmiServices?.prev ?? null, consensus: null, surprise: inds?.pmiServices?.surprise ?? null, trend: inds?.pmiServices?.trend ?? null, lastUpdated: "" },
    gdp:          { value: inds?.gdp?.value ?? null,          prev: inds?.gdp?.prev ?? null,          consensus: null, surprise: inds?.gdp?.surprise ?? null,          trend: inds?.gdp?.trend ?? null,          lastUpdated: "" },
    retailSales:  { value: inds?.retailSales?.value ?? null,  prev: inds?.retailSales?.prev ?? null,  consensus: null, surprise: inds?.retailSales?.surprise ?? null,  trend: inds?.retailSales?.trend ?? null,  lastUpdated: "" },
    unemployment: { value: inds?.unemployment?.value ?? null, prev: inds?.unemployment?.prev ?? null, consensus: null, surprise: inds?.unemployment?.surprise ?? null, trend: inds?.unemployment?.trend ?? null, lastUpdated: "" },
    employment:   { value: inds?.employment?.value ?? null,   prev: inds?.employment?.prev ?? null,   consensus: null, surprise: inds?.employment?.surprise ?? null,   trend: inds?.employment?.trend ?? null,   lastUpdated: "" },
  };

  const macroScore = calcMacroScore(forScoring, phase);
  const biasText   = biasLabel(macroScore);
  const biasCls    = biasColor(macroScore);
  const phaseInfo  = PHASES[phase];
  const yield10Y   = yields?.yields[currency] ?? null;
  const spread10Y  = yields?.spreads[currency] ?? null;
  const borderCls  = macroScore >= 4 ? "border-green-200" : macroScore <= -4 ? "border-red-200" : "border-gray-200";

  // Consensus = taux attendu à la prochaine réunion CB
  // Priorité : ratePath (OIS temps réel) > rateExp (snapshot statique)
  const rateConsensus = (() => {
    const rate = inds?.policyRate?.value ?? null;
    if (rate === null) return null;
    // OIS live
    if (ratePath && ratePath.meetings.length > 0) {
      const next = ratePath.meetings[0];
      if (next.probMovePct > 50) {
        return next.probIsCut
          ? parseFloat((rate - 0.25).toFixed(2))
          : parseFloat((rate + 0.25).toFixed(2));
      }
      return parseFloat(rate.toFixed(2));
    }
    // Fallback snapshot statique (CHF / si rateprobability indispo)
    if (!rateExp) return null;
    const desc = rateExp.prob_desc.toLowerCase();
    if (desc.includes("no change")) return parseFloat(rate.toFixed(2));
    if (rateExp.direction === "cut"  && rateExp.prob_pct > 50) return parseFloat((rate - 0.25).toFixed(2));
    if (rateExp.direction === "hike" && rateExp.prob_pct > 50) return parseFloat((rate + 0.25).toFixed(2));
    return parseFloat(rate.toFixed(2));
  })();

  return (
    <div className={`bg-white border rounded-xl overflow-hidden ${borderCls}`}>
      {/* Header */}
      <div className="px-4 pt-3 pb-2">
        <div className="flex items-center justify-between mb-1">
          <div className="flex items-center gap-2">
            <span className="text-2xl leading-none">{meta.flag}</span>
            <div>
              <div className="font-semibold text-sm text-gray-900">{currency}</div>
              <div className="text-[10px] text-gray-400">{meta.cbShort} · {meta.name}</div>
            </div>
          </div>
          <div className="text-right">
            {loading
              ? <Loader2 size={15} className="animate-spin text-gray-300" />
              : <>
                  <div className={`text-sm font-bold ${biasCls}`}>{biasText}</div>
                  <div className="text-[10px] text-gray-400">Score : {macroScore > 0 ? "+" : ""}{macroScore}</div>
                </>
            }
          </div>
        </div>
        <div className="flex items-center justify-between">
          <div className={`text-[10px] font-medium ${phaseInfo.color}`}>{phaseInfo.label}</div>
          {fromCache && cacheAge && (
            <div className="flex items-center gap-0.5 text-[9px] text-amber-500" title="Données issues du cache local — API indisponible lors du dernier chargement">
              <Database size={9} />
              <span>cache {cacheAge}</span>
            </div>
          )}
        </div>
      </div>

      {/* ── Probabilités OIS (rateprobability.com) ─────────────────────────── */}
      {ratePath && ratePath.meetings.length > 0 ? (
        <div className="mx-4 mb-2 px-3 py-2 bg-gray-50 rounded-lg">
          {/* Header */}
          <div className="flex items-center justify-between mb-1">
            <span className="text-[9px] font-semibold text-gray-400 uppercase tracking-wider">OIS · marchés</span>
            <span className="text-[9px] text-gray-400">au {ratePath.asOf}</span>
          </div>

          {/* Pic + taux fin d'année */}
          {ratePath.peakMeeting && (
            <div className="flex items-center justify-between text-[10px] mb-1.5">
              <span>
                <span className="text-gray-500">Pic </span>
                <span className="font-semibold text-gray-800">{ratePath.peakMeeting.label}</span>
                <span className={`ml-1 font-bold ${ratePath.peakMeeting.probIsCut ? "text-green-600" : "text-red-500"}`}>
                  {ratePath.peakMeeting.probMovePct.toFixed(0)}%
                  {ratePath.peakMeeting.probIsCut ? " ▼" : " ▲"}
                  {ratePath.peakMeeting.changeBps > 0.5 &&
                    <span className="font-normal text-gray-400"> +{ratePath.peakMeeting.changeBps.toFixed(0)}bps</span>
                  }
                </span>
              </span>
              {ratePath.yearEndImplied !== null && (
                <span className="text-gray-400 text-[9px]">
                  fin d&apos;an {ratePath.yearEndImplied.toFixed(2)}%
                </span>
              )}
            </div>
          )}

          {/* Timeline réunion par réunion */}
          <div className="flex flex-col gap-[3px]">
            {ratePath.meetings.slice(0, 6).map(m => (
              <div key={m.dateIso} className="flex items-center gap-1.5">
                <span className="text-[9px] text-gray-400 w-11 shrink-0 tabular-nums">{m.label}</span>
                <div className="flex-1 h-1.5 bg-gray-200 rounded-full overflow-hidden">
                  <div
                    className={`h-full rounded-full transition-all ${m.probIsCut ? "bg-green-400" : "bg-red-400"}`}
                    style={{ width: `${m.probMovePct}%` }}
                  />
                </div>
                <span className={`text-[9px] w-7 text-right tabular-nums shrink-0 ${m.probMovePct >= 50 ? "font-bold text-gray-800" : "text-gray-400"}`}>
                  {m.probMovePct.toFixed(0)}%
                </span>
              </div>
            ))}
          </div>
        </div>
      ) : rateExp ? (
        /* Fallback snapshot statique (ex: CHF sans données OIS) */
        <div className="mx-4 mb-2 px-3 py-1.5 bg-gray-50 rounded-lg text-xs leading-snug">
          <span className="font-semibold">{rateExp.direction === "hike" ? "▲" : "▼"} {rateExp.bps} bps</span>
          <span className="text-gray-500"> · {rateExp.prob_pct}% prob. </span>
          <span className={`font-medium ${rateExp.prob_desc.includes("no change") ? "text-gray-600" : rateExp.direction === "hike" ? "text-red-600" : "text-green-600"}`}>
            {rateExp.prob_desc}
          </span>
        </div>
      ) : null}

      {/* ── Indicateurs macro — organisation "prisme" ─────────────────────── */}
      <div className="px-4 pb-2">

        {/* ── POLITIQUE MONÉTAIRE ─────────────────────────────────────────── */}
        <SectionHeader label="Politique monétaire" />
        <Row label="Taux directeur" ind={inds?.policyRate ?? null} unit="%" consensus={rateConsensus} />
        <div className="flex items-center justify-between py-1.5 text-xs border-b border-gray-50">
          <span className="text-gray-500 text-xs">10Y Yield</span>
          <span className="font-semibold text-gray-800 tabular-nums text-xs">
            {yield10Y !== null ? `${yield10Y.toFixed(2)}%` : "—"}
            {spread10Y !== null && (
              <span className={`ml-1 text-[10px] ${spread10Y > 0 ? "text-green-600" : "text-red-600"}`}>
                ({spread10Y > 0 ? "+" : ""}{spread10Y}bps vs US)
              </span>
            )}
          </span>
        </div>

        {/* ── INFLATION ───────────────────────────────────────────────────── */}
        <SectionHeader label="Inflation" />
        <Row label="CPI Core YoY"   ind={inds?.cpiCore    ?? null} unit="%" consensus={fc?.cpiCore ?? fc?.cpi ?? null} surpriseVsCons={fc?.cpiSurprise ?? null} />
        <Row
          label={(() => {
            const isQoQ = (inds?.cpiCoreMoM as (Ind & { isQoQ?: boolean }) | null)?.isQoQ;
            return isQoQ ? "Core CPI QoQ" : "Core CPI MoM";
          })()}
          ind={inds?.cpiCoreMoM ?? null}
          unit="%"
          tooltip={(() => {
            const raw = (inds?.cpiCoreMoM as (Ind & { _raw?: { last: number; prev: number; refMonth: string } }) | null)?._raw;
            const base = "=Core Inflation Rate MoM";
            return raw ? `${base} — Index: last=${raw.last}  prev=${raw.prev}  ref=${raw.refMonth}` : base;
          })()}
        />
        <Row label="Inflation YoY"  ind={inds?.cpiYoY     ?? null} unit="%" />
        <Row label="CPI MoM"        ind={inds?.cpiMoM     ?? null} unit="%" consensus={fc?.cpiMoM ?? null} />
        <Row
          label="CPI Index MoM%"
          ind={inds?.cpiIndex ?? null}
          unit="%"
          tooltip={(() => {
            const raw = (inds?.cpiIndex as (Ind & { _raw?: { last: number; prev: number; refMonth: string } }) | null)?._raw;
            return raw ? `Index: last=${raw.last}  prev=${raw.prev}  ref=${raw.refMonth}` : null;
          })()}
        />

        {/* ── CROISSANCE ──────────────────────────────────────────────────── */}
        <SectionHeader label="Croissance" />
        <Row label="PIB (QoQ%)"     ind={inds?.gdp      ?? null} unit="%" consensus={fc?.gdp ?? null} surpriseVsCons={fc?.gdpSurprise ?? null} />
        <Row label="PMI Composite"  ind={inds?.pmiComposite ?? null} warn={!inds?.pmiComposite} consensus={fc?.pmiComposite ?? null} surpriseVsCons={fc?.pmiCompositeSurprise ?? null} />

        {/* ── EMPLOI ──────────────────────────────────────────────────────── */}
        <SectionHeader label="Emploi" />
        {/* Variation emploi = NFP/Employment Change en milliers — ex: +115k = 115 000 emplois créés */}
        <Row label="Variation emploi" ind={inds?.employment  ?? null} unit="k" warn={!inds?.employment} consensus={fc?.employment ?? null} surpriseVsCons={fc?.employmentSurprise ?? null} />
        <Row label="Taux de chômage"  ind={inds?.unemployment ?? null} unit="%" invertSurprise consensus={fc?.unemployment ?? null} surpriseVsCons={fc?.unemploymentSurprise ?? null} />

        {/* ── Données supplémentaires (expanded) ──────────────────────────── */}
        {expanded && (
          <>
            {/* PMI détail */}
            <SectionHeader label="PMI détail" />
            <Row label="PMI Mfg"       ind={inds?.pmiMfg      ?? null} warn={!inds?.pmiMfg}       consensus={fc?.pmiMfg      ?? null} surpriseVsCons={fc?.pmiMfgSurprise      ?? null} />
            <Row label="PMI Services"  ind={inds?.pmiServices ?? null} warn={!inds?.pmiServices}   consensus={fc?.pmiSvc      ?? null} surpriseVsCons={fc?.pmiSvcSurprise      ?? null} />
            <Row label="Ventes détail" ind={inds?.retailSales ?? null} unit="%" warn={!inds?.retailSales} consensus={fc?.retailSales ?? null} surpriseVsCons={fc?.retailSalesSurprise ?? null} />

            {/* Géopolitique */}
            <SectionHeader label="Géopolitique" />
            {inds?.tradeBalance ? (
              <div className="flex items-center justify-between py-1.5 border-b border-gray-50">
                <span className="text-gray-500 text-xs">Balance comm.</span>
                <span className={`text-xs font-semibold tabular-nums ${(inds.tradeBalance.value ?? 0) >= 0 ? "text-green-600" : "text-red-500"}`}>
                  {(inds.tradeBalance.value ?? 0) >= 0 ? "+" : ""}{inds.tradeBalance.value?.toFixed(1)}B
                  <span className="text-[9px] text-gray-400 font-normal ml-0.5">
                    {(inds.tradeBalance.value ?? 0) >= 0 ? " surplus" : " déficit"}
                  </span>
                </span>
              </div>
            ) : null}
            {/* Profil énergie + matières premières */}
            {(() => {
              const profile = COUNTRY_PROFILES[currency];
              if (!profile) return null;
              const energyColor = profile.energy === "exporter" ? "text-green-700 bg-green-50" : profile.energy === "importer" ? "text-red-700 bg-red-50" : "text-gray-600 bg-gray-100";
              const energyLabel = profile.energy === "exporter" ? "🛢 Export. énergie" : profile.energy === "importer" ? "⚡ Import. énergie" : "⚖ Énergie ~neutre";
              return (
                <div className="py-1.5 border-b border-gray-50 space-y-1">
                  <div className="flex items-start justify-between gap-2">
                    <span className={`text-[9px] font-semibold px-1.5 py-0.5 rounded ${energyColor}`}>{energyLabel}</span>
                    <span className="text-[9px] text-gray-400 text-right leading-tight max-w-[55%]">{profile.energyNote}</span>
                  </div>
                  {profile.commodities.length > 0 && (
                    <div className="flex flex-wrap gap-1 pt-0.5">
                      {profile.commodities.map(c => (
                        <span key={c} className="text-[8px] bg-amber-50 text-amber-700 border border-amber-200 px-1.5 py-0.5 rounded-full">{c}</span>
                      ))}
                    </div>
                  )}
                </div>
              );
            })()}

            {/* ── Sentiment & Positionnement ──────────────────────────────── */}
            <SectionHeader label="Sentiment & Positionnement" />
            {sentiment ? (
              <div className="py-1.5 border-b border-gray-50">
                <div className="flex items-center justify-between text-xs mb-1">
                  <span className="text-gray-500 text-[10px]">{sentiment.pair} · Myfxbook</span>
                  <span className="text-[10px] tabular-nums">
                    <span className="text-green-600 font-semibold">{sentiment.longPct}% L</span>
                    <span className="text-gray-300 mx-0.5">/</span>
                    <span className="text-red-500 font-semibold">{sentiment.shortPct}% S</span>
                  </span>
                </div>
                {/* Barre visuelle long/short */}
                <div className="flex h-1.5 rounded-full overflow-hidden">
                  <div className="bg-green-400 transition-all" style={{ width: `${sentiment.longPct}%` }} />
                  <div className="bg-red-400 flex-1" />
                </div>
                {/* Signal contrarien */}
                {(sentiment.longPct >= 70 || sentiment.shortPct >= 70) && (
                  <p className={`text-[9px] mt-0.5 font-medium ${sentiment.longPct >= 70 ? "text-red-500" : "text-green-600"}`}>
                    {sentiment.longPct >= 70 ? "⚠ Retail très long — signal contrarien baissier" : "⚠ Retail très short — signal contrarien haussier"}
                  </p>
                )}
              </div>
            ) : (
              <div className="py-1 text-[10px] text-gray-300 border-b border-gray-50">— (Myfxbook indisponible)</div>
            )}

            {/* ── COT CFTC ────────────────────────────────────────────────── */}
            <div className="pt-1 pb-0.5">
              <span className="text-[9px] font-semibold text-gray-400 uppercase tracking-wider">COT — Hedge Funds</span>
            </div>
            {cot ? (
              <div className="py-1.5">
                <div className="flex items-center justify-between text-xs mb-1">
                  <span className="text-gray-500 text-[10px]">Lev. Money · {cot.weekDate}</span>
                  <span className="text-[10px] tabular-nums">
                    <span className="text-green-600 font-semibold">{cot.longPct}% L</span>
                    <span className="text-gray-300 mx-0.5">/</span>
                    <span className="text-red-500 font-semibold">{cot.shortPct}% S</span>
                    <span className="text-gray-400 ml-1">({cot.net > 0 ? "+" : ""}{cot.net.toLocaleString("fr-FR")})</span>
                  </span>
                </div>
                <div className="flex h-1.5 rounded-full overflow-hidden">
                  <div className="bg-green-400 transition-all" style={{ width: `${cot.longPct}%` }} />
                  <div className="bg-red-400 flex-1" />
                </div>
                {/* Divergence COT vs Sentiment */}
                {sentiment && Math.abs(cot.longPct - sentiment.longPct) >= 20 && (
                  <p className="text-[9px] mt-0.5 text-amber-600 font-medium">
                    ⚡ Divergence COT/Retail : {Math.abs(cot.longPct - sentiment.longPct)}pts
                  </p>
                )}
              </div>
            ) : (
              <div className="py-1 text-[10px] text-gray-300">— (CFTC indisponible)</div>
            )}
          </>
        )}
      </div>

      {/* Footer */}
      <div className="border-t border-gray-100 px-4 py-2 flex items-center justify-between">
        <NarrativeButton currency={currency} indicators={forScoring} macroScore={macroScore} />
        <button
          onClick={() => setExpanded((e) => !e)}
          className="flex items-center gap-1 text-[10px] text-gray-400 hover:text-gray-600"
        >
          {expanded ? <ChevronUp size={11} /> : <ChevronDown size={11} />}
          {expanded ? "Moins" : "Détails"}
        </button>
      </div>
    </div>
  );
}
