import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
import { api } from '../api.js';
import { useInvestisseur } from '../context/InvestisseurContext.jsx';
import { useUi } from '../context/UiContext.jsx';
import PageIcon from '../components/PageIcon.jsx';
import EmptyState from '../components/EmptyState.jsx';
import InvChart from '../components/InvChart.jsx';
import InvMensuelTable from '../components/InvMensuelTable.jsx';
import SuiviObjectifs from '../components/SuiviObjectifs.jsx';
import { fmtEUR, fmtDate, fmtStatut, memberLabel, today } from '../utils/format.js';
import { xirr } from '../utils/xirr.js';
import { usePagination } from '../hooks/usePagination.js';
import Pagination from '../components/Pagination.jsx';

const LOGOS_BASE = '/api/logos/';

/* ── TrendBadge ── */
function TrendBadge({ current, prev, invert = false }) {
  if (prev == null || prev === 0) return null;
  const diff = current - prev;
  const pct  = (diff / prev) * 100;
  const up   = diff > 0;
  const neutral = diff === 0;
  const good = neutral ? null : (invert ? !up : up);
  const color = neutral ? 'var(--text-muted)' : good ? '#16a34a' : '#dc2626';
  const bg    = neutral ? 'var(--surface-2)' : good ? 'rgba(34,197,94,0.12)' : 'rgba(239,68,68,0.12)';
  const arrow = neutral ? '→' : up ? '↗' : '↘';
  const label = `${up ? '+' : ''}${Math.abs(pct) < 10 ? pct.toFixed(1) : Math.round(pct)}%`;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 3,
      padding: '2px 8px', borderRadius: 20,
      background: bg, color, fontSize: '0.76em', fontWeight: 600, whiteSpace: 'nowrap',
    }}>
      {arrow} {label}
    </span>
  );
}


/* ── Sélecteur Plateforme ── */
function PlatSelector({ platOptions, selectedPlatName, onSelect }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    if (!open) return;
    const h = e => { if (!ref.current?.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', h);
    return () => document.removeEventListener('mousedown', h);
  }, [open]);

  const selected = platOptions.find(p => p.nom === selectedPlatName) || platOptions[0];

  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <div
        onClick={() => setOpen(v => !v)}
        style={{
          background: 'linear-gradient(135deg, #7c3aed 0%, #4f46e5 100%)',
          borderRadius: 10, padding: '12px 16px',
          boxShadow: open ? '0 6px 28px rgba(109,40,217,0.45)' : '0 4px 20px rgba(109,40,217,0.30)',
          cursor: 'pointer', userSelect: 'none', transition: 'box-shadow .15s',
        }}
      >
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
          <span style={{ fontSize: 'var(--fs-xs)', textTransform: 'uppercase', letterSpacing: '.06em', color: 'rgba(255,255,255,0.7)', fontWeight: 500 }}>
            Plateforme
          </span>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none"
            stroke="rgba(255,255,255,0.7)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"
            style={{ transform: open ? 'rotate(180deg)' : 'none', transition: 'transform .2s', flexShrink: 0 }}>
            <polyline points="6 9 12 15 18 9"/>
          </svg>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          {selected?.icon_filename && (
            <img src={`${LOGOS_BASE}${selected.icon_filename}`}
              width={28} height={28}
              style={{ objectFit: 'contain', borderRadius: 4, background: 'rgba(255,255,255,0.12)', padding: 2, flexShrink: 0 }}
              alt="" />
          )}
          <span style={{ color: '#fff', fontSize: '1.1rem', fontWeight: 700, lineHeight: 1.2 }}>
            {selected?.nom || '—'}
          </span>
        </div>
      </div>

      {open && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 6px)', left: 0, right: 0, zIndex: 200,
          background: 'var(--surface)', border: '1px solid var(--border)',
          borderRadius: 10, boxShadow: '0 8px 28px rgba(0,0,0,0.15)', overflow: 'hidden',
          maxHeight: 280, overflowY: 'auto',
        }}>
          {platOptions.map(p => (
            <div
              key={p.nom}
              onClick={() => { onSelect(p.nom); setOpen(false); }}
              style={{
                display: 'flex', alignItems: 'center', gap: 10,
                padding: '10px 14px', cursor: 'pointer',
                background: p.nom === selectedPlatName ? 'var(--surface-2)' : 'transparent',
                fontWeight: p.nom === selectedPlatName ? 700 : 400,
                fontSize: 'var(--fs-sm)',
                borderBottom: '1px solid var(--border)',
                transition: 'background .1s',
              }}
              onMouseEnter={e => { if (p.nom !== selectedPlatName) e.currentTarget.style.background = 'var(--surface-2)'; }}
              onMouseLeave={e => { if (p.nom !== selectedPlatName) e.currentTarget.style.background = 'transparent'; }}
            >
              {p.icon_filename ? (
                <img src={`${LOGOS_BASE}${p.icon_filename}`}
                  width={20} height={20}
                  style={{ objectFit: 'contain', flexShrink: 0, opacity: 0.8 }}
                  alt="" />
              ) : (
                <span style={{ width: 20, height: 20, borderRadius: 4, background: 'var(--surface-2)', flexShrink: 0, display: 'inline-block' }} />
              )}
              <span>{p.nom}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

/* ── Sélecteur Détenteur ── */
function DetenteurSelector({ detenteurOptions, selectedId, onSelect }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    if (!open) return;
    const h = e => { if (!ref.current?.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', h);
    return () => document.removeEventListener('mousedown', h);
  }, [open]);

  const selected = detenteurOptions.find(d => d.id === selectedId) || detenteurOptions[0];

  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <div
        onClick={() => setOpen(v => !v)}
        style={{
          background: 'linear-gradient(135deg, #0d9488 0%, #0891b2 100%)',
          borderRadius: 10, padding: '12px 16px',
          boxShadow: open ? '0 6px 22px rgba(13,148,136,0.45)' : '0 4px 16px rgba(13,148,136,0.3)',
          cursor: 'pointer', userSelect: 'none', transition: 'box-shadow .15s',
        }}
      >
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
          <span style={{ fontSize: 'var(--fs-xs)', textTransform: 'uppercase', letterSpacing: '.06em', color: 'rgba(255,255,255,0.7)', fontWeight: 500 }}>
            Détenteur
          </span>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none"
            stroke="rgba(255,255,255,0.7)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"
            style={{ transform: open ? 'rotate(180deg)' : 'none', transition: 'transform .2s', flexShrink: 0 }}>
            <polyline points="6 9 12 15 18 9"/>
          </svg>
        </div>
        <span style={{ color: '#fff', fontSize: '1rem', fontWeight: 700, lineHeight: 1.2 }}>
          {selected?.label || '—'}
        </span>
      </div>

      {open && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 6px)', left: 0, right: 0, zIndex: 200,
          background: 'var(--surface)', border: '1px solid var(--border)',
          borderRadius: 10, boxShadow: '0 8px 28px rgba(0,0,0,0.15)', overflow: 'hidden',
        }}>
          {detenteurOptions.map(d => (
            <div
              key={d.id}
              onClick={() => { onSelect(d.id); setOpen(false); }}
              style={{
                padding: '10px 14px', cursor: 'pointer',
                background: d.id === selectedId ? 'var(--surface-2)' : 'transparent',
                fontWeight: d.id === selectedId ? 700 : 400,
                fontSize: 'var(--fs-sm)',
                borderBottom: '1px solid var(--border)',
                transition: 'background .1s',
              }}
              onMouseEnter={e => { if (d.id !== selectedId) e.currentTarget.style.background = 'var(--surface-2)'; }}
              onMouseLeave={e => { if (d.id !== selectedId) e.currentTarget.style.background = 'transparent'; }}
            >
              {d.label}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

/* ── Sélecteur Année ── */
function AnneeSelector({ availableYears, selectedYear, onSelect }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    if (!open) return;
    const h = e => { if (!ref.current?.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', h);
    return () => document.removeEventListener('mousedown', h);
  }, [open]);

  const options = [
    { value: '', label: 'Depuis le début' },
    ...[...availableYears].sort((a, b) => b - a).map(y => ({ value: String(y), label: String(y) })),
  ];
  const displayLabel = selectedYear || 'Depuis le début';
  const isGlobal = !selectedYear;

  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <div
        onClick={() => setOpen(v => !v)}
        style={{
          background: 'linear-gradient(135deg, #7c3aed 0%, #4f46e5 100%)',
          borderRadius: 10, padding: '12px 16px',
          boxShadow: open ? '0 6px 28px rgba(109,40,217,0.45)' : '0 4px 20px rgba(109,40,217,0.30)',
          cursor: 'pointer', userSelect: 'none', transition: 'box-shadow .15s',
        }}
      >
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
          <span style={{ fontSize: 'var(--fs-xs)', textTransform: 'uppercase', letterSpacing: '.06em', color: 'rgba(255,255,255,0.7)', fontWeight: 500 }}>
            Période
          </span>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none"
            stroke="rgba(255,255,255,0.7)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"
            style={{ transform: open ? 'rotate(180deg)' : 'none', transition: 'transform .2s', flexShrink: 0 }}>
            <polyline points="6 9 12 15 18 9"/>
          </svg>
        </div>
        <span style={{ color: '#fff', fontSize: isGlobal ? '1rem' : '1.8rem', fontWeight: 700, lineHeight: 1.1 }}>
          {displayLabel}
        </span>
      </div>

      {open && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 6px)', left: 0, right: 0, zIndex: 200,
          background: 'var(--surface)', border: '1px solid var(--border)',
          borderRadius: 10, boxShadow: '0 8px 28px rgba(0,0,0,0.15)', overflow: 'hidden',
        }}>
          {options.map(opt => (
            <div
              key={opt.value}
              onClick={() => { onSelect(opt.value); setOpen(false); }}
              style={{
                padding: '10px 14px', cursor: 'pointer',
                background: opt.value === selectedYear ? 'var(--surface-2)' : 'transparent',
                fontWeight: opt.value === selectedYear ? 700 : 400,
                fontSize: 'var(--fs-sm)',
                borderBottom: '1px solid var(--border)',
                transition: 'background .1s',
              }}
              onMouseEnter={e => { if (opt.value !== selectedYear) e.currentTarget.style.background = 'var(--surface-2)'; }}
              onMouseLeave={e => { if (opt.value !== selectedYear) e.currentTarget.style.background = 'transparent'; }}
            >
              {opt.label}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════════
   Page principale
═══════════════════════════════════════════════════════════════ */
export default function Plateformes() {
  const { activeId, activeView, investisseurs } = useInvestisseur();
  const { displayMode, chartInterets, chartCapital, chartCashback } = useUi();
  const navigate = useNavigate();
  const location = useLocation();
  const [searchParams, setSearchParams] = useSearchParams();

  /* ── État données ── */
  const [allRows,      setAllRows]      = useState([]);
  const [allRembs,     setAllRembs]     = useState([]);
  const [allReinvests, setAllReinvests] = useState([]);
  const [plats,        setPlats]        = useState([]);
  const [allDepots,    setAllDepots]    = useState([]);
  const [allCorrections, setAllCorrections] = useState([]);
  const [loading,      setLoading]      = useState(false);

  /* ── État sélecteurs ── */
  /* selectedPlatName et activeTab sont dans l'URL pour survivre au retour arrière */
  const selectedPlatName    = searchParams.get('plat') || null;
  const setSelectedPlatName = (nom) => {
    try { localStorage.setItem('cl_plat_selected', nom); } catch {}
    setSearchParams(p => { const n = new URLSearchParams(p); n.set('plat', nom); return n; }, { replace: true });
  };
  const [selectedDetenteurId, setSelectedDetenteurId] = useState(() => { try { return localStorage.getItem('cl_plat_detenteur') || 'all'; } catch { return 'all'; } });
  const [selectedYear,        setSelectedYear]        = useState(() => { try { return localStorage.getItem('cl_plat_year') || String(new Date().getFullYear()); } catch { return String(new Date().getFullYear()); } });
  const [windowStart,         setWindowStart]         = useState(0);
  const [drDetaille, setDrDetaille] = useState(() => {
    try { return localStorage.getItem('cl_dr_plat_detaille') === 'true'; } catch { return false; }
  });
  const toggleDrDetaille = () => setDrDetaille(v => {
    const next = !v;
    try { localStorage.setItem('cl_dr_plat_detaille', String(next)); } catch {}
    return next;
  });
  const [rembDetaille, setRembDetaille] = useState(() => {
    try { return localStorage.getItem('cl_remb_plat_detaille') === 'true'; } catch { return false; }
  });
  const toggleRembDetaille = () => setRembDetaille(v => {
    const next = !v;
    try { localStorage.setItem('cl_remb_plat_detaille', String(next)); } catch {}
    return next;
  });

  const [rembInclureInterets, setRembInclureInterets] = useState(() => {
    try { return localStorage.getItem('cl_remb_plat_interets') !== 'false'; } catch { return true; }
  });
  const [rembInclureCapital, setRembInclureCapital] = useState(() => {
    try { return localStorage.getItem('cl_remb_plat_capital') === 'true'; } catch { return false; }
  });
  const [rembInclureCashback, setRembInclureCashback] = useState(() => {
    try { return localStorage.getItem('cl_remb_plat_cashback') === 'true'; } catch { return false; }
  });
  const [rembShowActual,    setRembShowActual]    = useState(true);
  const [rembShowProjected, setRembShowProjected] = useState(true);
  const [libIcons,      setLibIcons]      = useState({});
  const [allSimulRembs, setAllSimulRembs] = useState([]);
  const [pfuRates,      setPfuRates]      = useState([]);

  /* ── État UI ── */
  const activeTab    = searchParams.get('tab') || (() => { try { return localStorage.getItem('cl_plat_tab') || 'remboursements'; } catch { return 'remboursements'; } })();
  const setActiveTab = (tab) => {
    try { localStorage.setItem('cl_plat_tab', tab); } catch {}
    setSearchParams(p => { const n = new URLSearchParams(p); n.set('tab', tab); return n; }, { replace: true });
  };
  const [listFocused,  setListFocused]  = useState(false);

  /* ── Chargement ── */
  const load = async () => {
    if (!activeId && activeView !== 'all') return;
    setLoading(true);
    try {
      const scopeParams = activeView === 'all' ? { scope: 'all' } : {};
      const [rows, p, rembs, reinvests, depots, corrections, simulRembs, pfu] = await Promise.all([
        api.get('/investissements', scopeParams),
        api.get('/plateformes'),
        api.get('/remboursements', scopeParams),
        api.get('/reinvestissements', { scope: 'all' }),
        api.get('/depots-retraits', scopeParams),
        api.get('/corrections', scopeParams),
        api.get('/simul/all', scopeParams),
        api.get('/pfu'),
      ]);
      setAllRows(rows);
      setPlats(p);
      setAllRembs(rembs);
      setAllReinvests(reinvests);
      setAllDepots(depots);
      setAllCorrections(corrections);
      setAllSimulRembs(Array.isArray(simulRembs) ? simulRembs : []);
      setPfuRates(Array.isArray(pfu) ? pfu : []);
    } finally { setLoading(false); }
  };

  useEffect(() => { load(); /* eslint-disable-next-line */ }, [activeId, activeView]);

  /* ── Icônes bibliothèque ── */
  useEffect(() => {
    api.get('/icons').then(rows => {
      const m = {};
      rows.forEach(r => { m[r.name] = r.filename; });
      setLibIcons(m);
    }).catch(() => {});
  }, []);

  /* ── Options plateformes : dédupliquées par nom ── */
  const platOptions = useMemo(() => {
    const map = {};
    for (const r of allRows) {
      const nom = r.plateforme_nom || '—';
      if (!map[nom]) {
        const p = plats.find(pl => pl.id === r.plateforme_id);
        map[nom] = {
          nom,
          icon_filename: p?.icone_filename || p?.logo_filename || null,
          investi: 0,
        };
      }
      if (!map[nom].icon_filename) {
        const p = plats.find(pl => pl.id === r.plateforme_id);
        map[nom].icon_filename = p?.icone_filename || p?.logo_filename || null;
      }
      map[nom].investi += r.montant_investi || 0;
    }
    return Object.values(map).sort((a, b) => b.investi - a.investi);
  }, [allRows, plats]);

  /* ── Init sélecteur plateforme — préfère localStorage ── */
  useEffect(() => {
    if (!selectedPlatName && platOptions.length > 0) {
      const saved = (() => { try { return localStorage.getItem('cl_plat_selected'); } catch { return null; } })();
      const target = platOptions.find(p => p.nom === saved) ? saved : platOptions[0].nom;
      setSelectedPlatName(target);
    }
  }, [platOptions, selectedPlatName]);

  /* ── Investissements pour la plateforme sélectionnée ── */
  const platRows = useMemo(() =>
    allRows.filter(r => selectedPlatName && r.plateforme_nom === selectedPlatName),
    [allRows, selectedPlatName]
  );

  /* ── Options détenteur (visible seulement si plusieurs détenteurs distincts) ── */
  const detenteurOptions = useMemo(() => {
    const ids = [...new Set(platRows.map(r => r.investisseur_id).filter(v => v != null))];
    if (ids.length <= 1) return null;
    return [
      { id: 'all', label: 'Multi-détenteur' },
      ...ids.map(id => {
        const inv = investisseurs.find(i => i.id === id || String(i.id) === String(id));
        return { id: String(id), label: inv ? memberLabel(inv) : `Détenteur ${id}` };
      }),
    ];
  }, [platRows, investisseurs]);

  /* ── Vrai/faux multi-détenteur global (indépendant de la plateforme sélectionnée) ── */
  const multiDetenteur = new Set(plats.map(p => p.investisseur_id)).size > 1;

  /* ── Reset détenteur quand plateforme change (skip restauration initiale) ── */
  const isFirstPlatChange = useRef(true);
  useEffect(() => {
    if (isFirstPlatChange.current) { isFirstPlatChange.current = false; return; }
    setSelectedDetenteurId('all');
    try { localStorage.setItem('cl_plat_detenteur', 'all'); } catch {}
  }, [selectedPlatName]);

  /* ── Persistance selectedYear et selectedDetenteurId ── */
  useEffect(() => { try { localStorage.setItem('cl_plat_year', selectedYear); } catch {} }, [selectedYear]);
  useEffect(() => { try { localStorage.setItem('cl_plat_detenteur', selectedDetenteurId); } catch {} }, [selectedDetenteurId]);

  /* ── IDs des plateformes correspondant à la sélection nom + détenteur ── */
  const filteredPlatIds = useMemo(() => {
    if (!selectedPlatName) return new Set();
    const matching = plats.filter(p => p.nom === selectedPlatName);
    if (selectedDetenteurId === 'all') return new Set(matching.map(p => p.id));
    return new Set(matching.filter(p => String(p.investisseur_id) === String(selectedDetenteurId)).map(p => p.id));
  }, [plats, selectedPlatName, selectedDetenteurId]);

  /* ── Lignes filtrées (plateforme + détenteur) ── */
  const filteredRows = useMemo(() => {
    if (selectedDetenteurId === 'all' || !detenteurOptions) return platRows;
    return platRows.filter(r => String(r.investisseur_id) === String(selectedDetenteurId));
  }, [platRows, selectedDetenteurId, detenteurOptions]);

  /* ── Années disponibles (asc pour la barre de boutons, desc pour le dropdown) ── */
  const availableYearsAsc = useMemo(() => {
    const set = new Set(filteredRows.map(r => r.date_souscription?.slice(0,4)).filter(Boolean));
    return [...set].map(Number).sort((a, b) => a - b);
  }, [filteredRows]);

  const availableYears = useMemo(() => [...availableYearsAsc].reverse(), [availableYearsAsc]);

  /* Repositionne la fenêtre sur l'année courante à chaque changement de plateforme ── */
  useEffect(() => {
    if (!availableYearsAsc.length) return;
    const currentYear = new Date().getFullYear();
    const idx = availableYearsAsc.indexOf(currentYear);
    const pos = idx >= 0 ? idx : availableYearsAsc.length - 1;
    setWindowStart(Math.max(0, Math.min(Math.max(0, availableYearsAsc.length - 3), pos - 1)));
  }, [selectedPlatName]); // eslint-disable-line react-hooks/exhaustive-deps

  /* ── lastRembDateMap ── */
  const lastRembDateMap = useMemo(() => {
    const map = {};
    for (const rb of allRembs) {
      const id = rb.investissement_id;
      const d  = rb.date_remb?.slice(0,10);
      if (!id || !d) continue;
      if (!map[id] || d > map[id]) map[id] = d;
    }
    return map;
  }, [allRembs]);

  const isActiveAtEndOfYear = (r, yr) => {
    if (!yr) return true;
    const cutoff  = `${yr}-12-31`;
    const decStart = `${yr}-12-01`;
    if (r.date_souscription > cutoff) return false;
    const ACTIVE = ['en_cours', 'en_retard', 'procedure'];
    if (ACTIVE.includes(r.statut)) return true;
    const fin = r.date_cible ?? lastRembDateMap[r.id] ?? null;
    return !!fin && fin >= decStart;
  };

  /* ── Lignes pour les graphiques (filtrées par année) ── */
  const chartRows = useMemo(() => {
    if (!selectedYear) return filteredRows;
    return filteredRows.filter(r => isActiveAtEndOfYear(r, selectedYear));
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [filteredRows, selectedYear, lastRembDateMap]);

  /* ── Agrégats remboursements (filtrés par coupure année) ── */
  const rembParInv = useMemo(() => {
    const cutoff = selectedYear ? `${selectedYear}-12-31` : null;
    const map = {};
    for (const rb of allRembs) {
      if (!rb.investissement_id) continue;
      const d = rb.date_remb?.slice(0,10);
      if (!d || (cutoff && d > cutoff)) continue;
      const id = rb.investissement_id;
      if (!map[id]) map[id] = { capital: 0, interets_bruts: 0, interets_nets: 0 };
      map[id].capital        += rb.capital        || 0;
      map[id].interets_bruts += rb.interets_bruts || 0;
      map[id].interets_nets  += rb.interets_nets  || 0;
    }
    return map;
  }, [allRembs, selectedYear]);

  const capRembParInv = useMemo(() =>
    Object.fromEntries(Object.entries(rembParInv).map(([id, v]) => [id, v.capital])),
    [rembParInv]
  );

  const reinvestCumulParInv = useMemo(() => {
    const cutoff = selectedYear ? `${selectedYear}-12-31` : null;
    const map = {};
    for (const rv of allReinvests) {
      const d = rv.date_reinvestissement?.slice(0,10);
      if (!d || (cutoff && d > cutoff)) continue;
      map[rv.investissement_id] = (map[rv.investissement_id] || 0) + (rv.montant || 0);
    }
    return map;
  }, [allReinvests, selectedYear]);

  /* ── KPI rows (= chartRows : déjà filtrées par plateforme + détenteur + année) ── */
  const totals = useMemo(() => chartRows.reduce((acc, r) => {
    const capInv  = r.montant_investi + (reinvestCumulParInv[r.id] || 0);
    const capRemb = capRembParInv[r.id] || 0;
    acc.investi      += capInv;
    acc.cap_remb     += capRemb;
    acc.int_perc     += rembParInv[r.id]?.interets_bruts || 0;
    acc.int_perc_net += rembParInv[r.id]?.interets_nets  || 0;
    const capRestant = Math.max(0, capInv - capRemb);
    acc.encours += capRestant;
    if (['en_retard', 'procedure'].includes(r.statut)) acc.defaut += capRestant;
    return acc;
  }, { investi: 0, cap_remb: 0, int_perc: 0, int_perc_net: 0, encours: 0, defaut: 0 }),
  [chartRows, capRembParInv, rembParInv, reinvestCumulParInv]);

  /* ── Pagination onglet Investissements ── */
  const sortedChartRows = useMemo(() =>
    chartRows.slice().sort((a, b) => (a.date_souscription || '') < (b.date_souscription || '') ? -1 : 1),
    [chartRows]
  );
  const {
    pagedItems: pagedChartRows, page: platInvPage, setPage: setPlatInvPage,
    pageSize: platInvPageSize, setPageSize: setPlatInvPageSize,
    totalPages: platInvTotalPages, totalItems: platInvTotalItems, PAGE_SIZES: platInvPageSizes,
  } = usePagination(sortedChartRows, 'cl_pagesize_plat_inv', [selectedPlatName, selectedYear]);

  /* ── KPI N-1 (pour TrendBadge) ── */
  const prevTotals = useMemo(() => {
    const effectiveYear = selectedYear || String(new Date().getFullYear());
    const prevYear  = String(Number(effectiveYear) - 1);
    const cutoff    = `${prevYear}-12-31`;
    const prevRembParInv = {};
    for (const rb of allRembs) {
      if (!rb.investissement_id) continue;
      const d = rb.date_remb?.slice(0,10);
      if (!d || d > cutoff) continue;
      const id = rb.investissement_id;
      if (!prevRembParInv[id]) prevRembParInv[id] = { capital: 0, interets_bruts: 0, interets_nets: 0 };
      prevRembParInv[id].capital        += rb.capital        || 0;
      prevRembParInv[id].interets_bruts += rb.interets_bruts || 0;
      prevRembParInv[id].interets_nets  += rb.interets_nets  || 0;
    }
    const prevReinvest = {};
    for (const rv of allReinvests) {
      const d = rv.date_reinvestissement?.slice(0,10);
      if (!d || d > cutoff) continue;
      prevReinvest[rv.investissement_id] = (prevReinvest[rv.investissement_id] || 0) + (rv.montant || 0);
    }
    const prevRows = filteredRows.filter(r => isActiveAtEndOfYear(r, prevYear));
    return prevRows.reduce((acc, r) => {
      const capInv  = r.montant_investi + (prevReinvest[r.id] || 0);
      const capRemb = prevRembParInv[r.id]?.capital || 0;
      acc.investi      += capInv;
      acc.cap_remb     += capRemb;
      acc.int_perc     += prevRembParInv[r.id]?.interets_bruts || 0;
      acc.int_perc_net += prevRembParInv[r.id]?.interets_nets  || 0;
      const capRestant = Math.max(0, capInv - capRemb);
      acc.encours += capRestant;
      if (['en_retard', 'procedure'].includes(r.statut)) acc.defaut += capRestant;
      return acc;
    }, { investi: 0, cap_remb: 0, int_perc: 0, int_perc_net: 0, encours: 0, defaut: 0 });
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedYear, filteredRows, allRembs, allReinvests, lastRembDateMap]);

  /* ── XIRR agrégé (flux datés : investis + réinvestissements + remboursements + valorisation
     du capital restant dû pour les prêts non soldés, à la date de coupure) ── */
  const plateformeXirr = useMemo(() => {
    const cutoff = selectedYear ? `${selectedYear}-12-31` : today();
    const ids = new Set(chartRows.map(r => r.id));
    const flowsBrut = [];
    const flowsNet  = [];
    for (const r of chartRows) {
      if (!r.date_souscription) continue;
      flowsBrut.push({ amount: -r.montant_investi, date: r.date_souscription });
      flowsNet.push({ amount: -r.montant_investi, date: r.date_souscription });
    }
    for (const rv of allReinvests) {
      if (!ids.has(rv.investissement_id)) continue;
      const d = rv.date_reinvestissement?.slice(0, 10);
      if (!d || d > cutoff) continue;
      flowsBrut.push({ amount: -(rv.montant || 0), date: d });
      flowsNet.push({ amount: -(rv.montant || 0), date: d });
    }
    for (const rb of allRembs) {
      if (!ids.has(rb.investissement_id)) continue;
      const d = rb.date_remb?.slice(0, 10);
      if (!d || d > cutoff) continue;
      flowsBrut.push({ amount: (rb.capital || 0) + (rb.cashback || 0) + (rb.interets_bruts || 0), date: d });
      flowsNet.push({ amount: rb.net_recu || 0, date: d });
    }
    let estime = false;
    for (const r of chartRows) {
      const capInv     = r.montant_investi + (reinvestCumulParInv[r.id] || 0);
      const capRemb    = capRembParInv[r.id] || 0;
      const capRestant = Math.max(0, capInv - capRemb);
      if (capRestant > 0.01) {
        estime = true;
        flowsBrut.push({ amount: capRestant, date: cutoff });
        flowsNet.push({ amount: capRestant, date: cutoff });
      }
    }
    const byDate = (a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0);
    flowsBrut.sort(byDate);
    flowsNet.sort(byDate);
    return { brut: xirr(flowsBrut), net: xirr(flowsNet), estime, cutoff };
  }, [chartRows, allRembs, allReinvests, selectedYear, reinvestCumulParInv, capRembParInv]);

  const netMode = displayMode === 'net';
  const prevYearLabel = selectedYear ? Number(selectedYear) - 1 : new Date().getFullYear() - 1;

  if (!loading && plats.length === 0) {
    return (
      <>
        <div className="topbar">
          <h2><PageIcon name="plateforme" />Plateformes</h2>
        </div>
        <EmptyState />
      </>
    );
  }

  if (!loading && platOptions.length === 0) {
    return (
      <>
        <div className="topbar">
          <h2><PageIcon name="plateforme" />Plateformes</h2>
        </div>
        <EmptyState
          icon="📊"
          title="Aucun investissement pour le moment"
          message="Vos plateformes sont configurées, mais aucun investissement n'y a encore été ajouté. Ajoutez un investissement pour voir apparaître les données de vos plateformes."
          cta="Ajouter un investissement"
          to="/investissements?new=1"
        />
      </>
    );
  }

  return (
    <>
      <div className="topbar">
        <h2><PageIcon name="plateforme" />Plateformes</h2>
      </div>

      {/* ── Graphiques + Sélecteurs ── */}
      {!listFocused && <div className="charts-row">
        <InvChart
          rows={chartRows}
          remboursements={allRembs}
          reinvestissements={allReinvests}
          platYear={selectedYear}
        />

        {/* ── Panneau sélecteurs (remplace DistributionChart) ── */}
        <div className="dist-chart-wrap" style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {platOptions.length > 0 && (
            <PlatSelector
              platOptions={platOptions}
              selectedPlatName={selectedPlatName}
              onSelect={nom => setSelectedPlatName(nom)}
            />
          )}
          {detenteurOptions && (
            <DetenteurSelector
              detenteurOptions={detenteurOptions}
              selectedId={selectedDetenteurId}
              onSelect={setSelectedDetenteurId}
            />
          )}
          <AnneeSelector
            availableYears={availableYears}
            selectedYear={selectedYear}
            onSelect={setSelectedYear}
          />
        </div>
      </div>}

      {/* ── KPIs ── */}
      {!listFocused && <div className="dr-kpi-row" style={{ gridTemplateColumns: 'repeat(6, 1fr)' }}>

        {/* 1 — Capital investi */}
        <div className="kpi">
          <div className="label">Capital investi</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '4px 0 0' }}>
            <span style={{ fontSize: '1.35rem', fontWeight: 700 }}>{fmtEUR(totals.encours)}</span>
            <TrendBadge current={totals.encours} prev={prevTotals.encours} />
          </div>
          <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>
            {fmtEUR(prevTotals.encours)} en {prevYearLabel}
          </div>
        </div>

        {/* 2 — Investissements à risque */}
        <div className="kpi">
          <div className="label">Investissements à risque</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '4px 0 0' }}>
            <span style={{ fontSize: '1.35rem', fontWeight: 700 }} className={totals.defaut > 0 ? 'danger' : ''}>
              {fmtEUR(totals.defaut)}
            </span>
            {totals.defaut > 0 && <TrendBadge current={totals.defaut} prev={prevTotals.defaut} invert={true} />}
          </div>
          <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>
            {fmtEUR(prevTotals.defaut)} en {prevYearLabel}
          </div>
        </div>

        {/* 3 — Investissements depuis le début */}
        <div className="kpi">
          <div className="label">Investissements depuis le début</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '4px 0 0' }}>
            <span style={{ fontSize: '1.35rem', fontWeight: 700 }}>{fmtEUR(totals.investi)}</span>
            <TrendBadge current={totals.investi} prev={prevTotals.investi} />
          </div>
          <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>
            {fmtEUR(prevTotals.investi)} en {prevYearLabel}
          </div>
        </div>

        {/* 4 — Capital remboursé */}
        <div className="kpi">
          <div className="label">Capital remboursé</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '4px 0 0' }}>
            <span style={{ fontSize: '1.35rem', fontWeight: 700 }}>{fmtEUR(totals.cap_remb)}</span>
            <TrendBadge current={totals.cap_remb} prev={prevTotals.cap_remb} />
          </div>
          <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>
            {fmtEUR(prevTotals.cap_remb)} en {prevYearLabel}
          </div>
        </div>

        {/* 5 — Intérêts perçus */}
        <div className="kpi">
          <div className="label">Intérêts perçus — {netMode ? 'Net' : 'Brut'}</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '4px 0 0' }}>
            <span style={{ fontSize: '1.35rem', fontWeight: 700 }}>
              {fmtEUR(netMode ? totals.int_perc_net : totals.int_perc)}
            </span>
            <TrendBadge
              current={netMode ? totals.int_perc_net : totals.int_perc}
              prev={netMode ? prevTotals.int_perc_net : prevTotals.int_perc}
            />
          </div>
          <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>
            {fmtEUR(netMode ? prevTotals.int_perc_net : prevTotals.int_perc)} en {prevYearLabel}
          </div>
        </div>

        {/* 6 — XIRR */}
        {(() => {
          const rendement = netMode ? plateformeXirr.net : plateformeXirr.brut;
          const cutoffLabel = selectedYear ? `31/12/${selectedYear}` : "aujourd'hui";
          const xirrExplication =
            `XIRR (taux de rendement interne actualisé) : taux annualisé calculé à partir de l'ensemble des flux réels datés ` +
            `des prêts de cette sélection (versements initiaux, réinvestissements, remboursements ${netMode ? 'nets, après fiscalité' : 'bruts, avant fiscalité'}). ` +
            `Chaque flux est pondéré par sa date exacte.\n\n` +
            (plateformeXirr.estime
              ? `Certains prêts ne sont pas encore soldés : leur capital restant dû est ajouté en flux final, valorisé au ${cutoffLabel} — c'est donc une estimation, pas un taux définitif.`
              : 'Tous les prêts de cette sélection sont soldés : taux définitif.');
          return (
            <div className="kpi">
              <div className="label" style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
                <span>
                  XIRR — {netMode ? 'Net' : 'Brut'}
                  {plateformeXirr.estime && rendement !== null ? <span className="text-muted"> (estimé)</span> : ''}
                </span>
                <span
                  className="cell-tooltip tooltip-down"
                  data-tooltip={xirrExplication}
                  style={{ display: 'inline-flex', color: 'var(--text-muted)' }}
                >
                  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                    <circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/>
                  </svg>
                </span>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '4px 0 0' }}>
                <span
                  style={{ fontSize: '1.35rem', fontWeight: 700, color: rendement !== null ? (rendement >= 0 ? 'var(--success)' : 'var(--danger)') : 'var(--text-muted)' }}
                >
                  {rendement !== null
                    ? `${(rendement * 100).toLocaleString('fr-FR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} %`
                    : 'Aucun remboursement'}
                </span>
              </div>
              <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>
                Valorisé au {cutoffLabel}
              </div>
            </div>
          );
        })()}
      </div>}

      {/* ── Onglets ── */}
      <div className="dr-tabs">
        <button className={`dr-tab${activeTab === 'remboursements' ? ' active' : ''}`}
          onClick={() => setActiveTab('remboursements')}>Remboursements</button>
        <button className={`dr-tab${activeTab === 'depots-retraits' ? ' active' : ''}`}
          onClick={() => setActiveTab('depots-retraits')}>Dépôts / Retraits</button>
        <button className={`dr-tab${activeTab === 'capital-investi' ? ' active' : ''}`}
          onClick={() => setActiveTab('capital-investi')}>Capital investi</button>
        <button className={`dr-tab${activeTab === 'investissements' ? ' active' : ''}`}
          onClick={() => setActiveTab('investissements')}>Investissements</button>
      </div>

      {/* ====== ONGLET REMBOURSEMENTS ====== */}
      {activeTab === 'remboursements' && (() => {
        const ICONS_BASE = '/api/icons-files/';
        const currentYear  = new Date().getFullYear();
        const currentMonth = new Date().getMonth() + 1;
        const displayYear  = selectedYear ? Number(selectedYear) : currentYear;
        const MOIS_LONG = ['Jan.','Fév.','Mars','Avr.','Mai','Juin','Juil.','Août','Sep.','Oct.','Nov.','Déc.'];

        const hexToRgba = (hex, a) => {
          if (!hex || hex.length < 7) return `rgba(79,168,232,${a})`;
          const r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16);
          return `rgba(${r},${g},${b},${a})`;
        };

        const RIcon = ({ name, size = 26, active }) => {
          const filename = libIcons[name];
          if (filename) return (
            <img src={ICONS_BASE + filename} className="app-lib-icon" width={size} height={size}
              aria-hidden="true"
              style={{ opacity: active ? 1 : 0.35, display: 'block', transition: 'opacity .15s' }} />
          );
          return <span style={{ width: size, height: size, display: 'block', borderRadius: 4,
            background: 'var(--text-muted)', opacity: active ? 0.55 : 0.2, transition: 'opacity .15s' }} />;
        };

        const getPfuReduction = (yr) => {
          if (!pfuRates?.length) return 0.3;
          const r = pfuRates.find(p => p.annee === yr) ?? pfuRates.reduce((best, p) => p.annee > best.annee ? p : best, pfuRates[0]);
          return r ? (r.prelev_sociaux + r.impot_revenu) / 100 : 0.3;
        };

        // Investissements filtrés
        const filteredInvIds = new Set(filteredRows.map(r => r.id));
        const multiHolder = filteredPlatIds.size > 1;

        // Map plateforme_id → nom détenteur
        const detenteurByPlatId = {};
        for (const pid of filteredPlatIds) {
          const p = plats.find(pl => pl.id === pid);
          detenteurByPlatId[pid] = p?.investisseur_nom || String(pid);
        }

        // Agréger rembs réels par investissement par mois-key
        const rembByInvByMonth = {};
        for (const rb of allRembs) {
          if (!filteredInvIds.has(rb.investissement_id)) continue;
          const d = rb.date_remb?.slice(0, 10);
          if (!d) continue;
          if (selectedYear && d.slice(0, 4) !== selectedYear) continue;
          const moisStr = d.slice(0, 7);
          const id = rb.investissement_id;
          if (!rembByInvByMonth[id]) rembByInvByMonth[id] = {};
          if (!rembByInvByMonth[id][moisStr]) rembByInvByMonth[id][moisStr] = { interets_bruts: 0, interets_nets: 0, cashback: 0, capital: 0 };
          rembByInvByMonth[id][moisStr].interets_bruts += rb.interets_bruts || 0;
          rembByInvByMonth[id][moisStr].interets_nets  += rb.interets_nets  || 0;
          rembByInvByMonth[id][moisStr].cashback        += rb.cashback       || 0;
          rembByInvByMonth[id][moisStr].capital         += rb.capital        || 0;
        }

        // Agréger projections par investissement par mois-key
        const simulByInvByMonth = {};
        for (const sr of allSimulRembs) {
          if (!filteredInvIds.has(sr.investissement_id)) continue;
          const d = sr.date_prevue?.slice(0, 10);
          if (!d) continue;
          if (selectedYear && d.slice(0, 4) !== selectedYear) continue;
          const moisStr = d.slice(0, 7);
          const id = sr.investissement_id;
          if (!simulByInvByMonth[id]) simulByInvByMonth[id] = {};
          if (!simulByInvByMonth[id][moisStr]) simulByInvByMonth[id][moisStr] = { capital_prevu: 0, interets_prevus: 0 };
          simulByInvByMonth[id][moisStr].capital_prevu   += sr.capital_prevu   || 0;
          simulByInvByMonth[id][moisStr].interets_prevus += sr.interets_prevus || 0;
        }

        // buildCellValue : renvoie { value, projected } | null
        const buildCellValue = (invId, mIdx) => {
          const m = mIdx + 1;
          const moisStr = `${displayYear}-${String(m).padStart(2, '0')}`;
          const isFuture  = displayYear > currentYear || (displayYear === currentYear && m > currentMonth);
          const isCurrent = displayYear === currentYear && m === currentMonth;
          const pfu = getPfuReduction(displayYear);

          if (isFuture) {
            if (!rembShowProjected) return null;
            const proj = simulByInvByMonth[invId]?.[moisStr];
            if (!proj) return null;
            let v = 0;
            if (rembInclureInterets) v += netMode ? proj.interets_prevus * (1 - pfu) : proj.interets_prevus;
            if (rembInclureCapital)  v += proj.capital_prevu ?? 0;
            return v > 0 ? { value: v, projected: true } : null;
          }

          if (isCurrent) {
            const remb = rembByInvByMonth[invId]?.[moisStr];
            const proj = simulByInvByMonth[invId]?.[moisStr];
            let real = 0;
            if (rembShowActual && remb) {
              if (rembInclureInterets)  real += netMode ? remb.interets_nets  : remb.interets_bruts;
              if (rembInclureCashback)  real += remb.cashback ?? 0;
              if (rembInclureCapital)   real += remb.capital  ?? 0;
            }
            let projAmt = 0;
            // simul/all ne filtre pas NOT EXISTS → guard real===0 obligatoire pour éviter le doublon
            if (rembShowProjected && proj && real === 0) {
              if (rembInclureInterets)  projAmt += netMode ? proj.interets_prevus * (1 - pfu) : proj.interets_prevus;
              if (rembInclureCapital)   projAmt += proj.capital_prevu ?? 0;
            }
            const val = real + projAmt;
            return val > 0 ? { value: val, projected: projAmt > 0 && real === 0 } : null;
          }

          // Mois passé
          if (!rembShowActual) return null;
          const remb = rembByInvByMonth[invId]?.[moisStr];
          if (!remb) return null;
          let v = 0;
          if (rembInclureInterets)  v += netMode ? remb.interets_nets  : remb.interets_bruts;
          if (rembInclureCashback)  v += remb.cashback ?? 0;
          if (rembInclureCapital)   v += remb.capital  ?? 0;
          return v > 0 ? { value: v, projected: false } : null;
        };

        // Construire la grille
        const makeGrid = (invs) => invs
          .map(r => ({
            inv: r,
            months: Array.from({ length: 12 }, (_, i) => buildCellValue(r.id, i)),
          }))
          .filter(g => g.months.some(v => v !== null))
          .sort((a, b) => (a.inv.date_souscription || '') < (b.inv.date_souscription || '') ? -1 : 1);

        // Grouper par détenteur si détaillé
        const groups = (() => {
          if (rembDetaille && multiHolder) {
            const byPlatId = {};
            for (const pid of filteredPlatIds) {
              const invs = filteredRows.filter(r => r.plateforme_id === pid);
              const grid = makeGrid(invs);
              if (grid.length > 0) byPlatId[pid] = { label: detenteurByPlatId[pid], grid };
            }
            return Object.entries(byPlatId);
          }
          return [[null, { label: null, grid: makeGrid(filteredRows) }]];
        })();

        const allGridRows = groups.flatMap(([, g]) => g.grid);
        const monthTotals = Array.from({ length: 12 }, (_, i) =>
          allGridRows.reduce((s, r) => s + (r.months[i]?.value ?? 0), 0));
        const grandTotal = monthTotals.reduce((s, v) => s + v, 0);

        const visibleYearsR = availableYearsAsc.length
          ? availableYearsAsc.slice(windowStart, windowStart + 3)
          : [currentYear];
        const canPrevR = windowStart > 0;
        const canNextR = windowStart + 3 < availableYearsAsc.length;

        const colClass = (i, projected = false) =>
          `tip-td-num${projected ? ' tip-projected' : ''}${displayYear === currentYear && i === currentMonth - 1 ? ' tip-col-current' : ''}`;

        return (
          <div style={{ padding: '0 24px' }}>
            <div className="solde-chart-wrap" style={{ padding: '24px 24px 16px', marginBottom: 24 }}>
              <div className="solde-chart-header" style={{ marginBottom: 16 }}>
                <div className="solde-chart-info">
                  <div style={{ display: 'flex', alignItems: 'center', gap: 5, flexWrap: 'wrap', marginBottom: 2 }}>
                    {rembInclureInterets && (
                      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4,
                        background: hexToRgba(chartInterets, 0.12), borderRadius: 5, padding: '3px 8px' }}>
                        <span style={{ width: 7, height: 7, borderRadius: 2, background: chartInterets, flexShrink: 0 }} />
                        <span style={{ fontSize: 13, color: chartInterets, fontWeight: 600 }}>
                          {netMode ? 'Intérêts nets' : 'Intérêts bruts'}
                        </span>
                      </span>
                    )}
                    {rembInclureCapital && (
                      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4,
                        background: hexToRgba(chartCapital, 0.12), borderRadius: 5, padding: '3px 8px' }}>
                        <span style={{ width: 7, height: 7, borderRadius: 2, background: chartCapital, flexShrink: 0 }} />
                        <span style={{ fontSize: 13, color: chartCapital, fontWeight: 600 }}>Capital</span>
                      </span>
                    )}
                    {rembInclureCashback && (
                      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4,
                        background: hexToRgba(chartCashback, 0.12), borderRadius: 5, padding: '3px 8px' }}>
                        <span style={{ width: 7, height: 7, borderRadius: 2, background: chartCashback, flexShrink: 0 }} />
                        <span style={{ fontSize: 13, color: chartCashback, fontWeight: 600 }}>Cashback</span>
                      </span>
                    )}
                    {!rembInclureInterets && !rembInclureCapital && !rembInclureCashback && (
                      <span style={{ fontSize: 13, color: 'var(--text-muted)' }}>—</span>
                    )}
                    <span style={{ fontSize: 13, color: 'var(--text-muted)' }}>
                      · {selectedYear || 'Toutes les années'}
                    </span>
                  </div>
                  <div className="solde-chart-value">{fmtEUR(grandTotal)}</div>
                </div>
                <div className="solde-chart-controls" style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
                  {/* Bouton Intérêts */}
                  <button
                    title={rembInclureInterets ? 'Intérêts inclus — cliquer pour exclure' : 'Cliquer pour inclure les intérêts'}
                    onClick={() => setRembInclureInterets(v => { const n = !v; try { localStorage.setItem('cl_remb_plat_interets', String(n)); } catch {} return n; })}
                    style={{ background: rembInclureInterets ? hexToRgba(chartInterets, 0.13) : 'none',
                      border: '1px solid ' + (rembInclureInterets ? chartInterets : 'transparent'),
                      borderRadius: 8, padding: '4px 6px', cursor: 'pointer', display: 'flex', alignItems: 'center',
                      transition: 'background .15s,border-color .15s', marginRight: 2 }}>
                    <RIcon name="interets" active={rembInclureInterets} />
                  </button>
                  {/* Bouton Capital */}
                  <button
                    title={rembInclureCapital ? 'Capital inclus — cliquer pour exclure' : 'Cliquer pour inclure le capital'}
                    onClick={() => setRembInclureCapital(v => { const n = !v; try { localStorage.setItem('cl_remb_plat_capital', String(n)); } catch {} return n; })}
                    style={{ background: rembInclureCapital ? hexToRgba(chartCapital, 0.13) : 'none',
                      border: '1px solid ' + (rembInclureCapital ? chartCapital : 'transparent'),
                      borderRadius: 8, padding: '4px 6px', cursor: 'pointer', display: 'flex', alignItems: 'center',
                      transition: 'background .15s,border-color .15s', marginRight: 2 }}>
                    <RIcon name="capital" active={rembInclureCapital} />
                  </button>
                  {/* Bouton Cashback */}
                  <button
                    title={rembInclureCashback ? 'Cashback inclus — cliquer pour exclure' : 'Cliquer pour inclure le cashback'}
                    onClick={() => setRembInclureCashback(v => { const n = !v; try { localStorage.setItem('cl_remb_plat_cashback', String(n)); } catch {} return n; })}
                    style={{ background: rembInclureCashback ? hexToRgba(chartCashback, 0.13) : 'none',
                      border: '1px solid ' + (rembInclureCashback ? chartCashback : 'transparent'),
                      borderRadius: 8, padding: '4px 6px', cursor: 'pointer', display: 'flex', alignItems: 'center',
                      transition: 'background .15s,border-color .15s', marginRight: 2 }}>
                    <RIcon name="cashback" active={rembInclureCashback} />
                  </button>
                  {/* Sélecteur années */}
                  <div className="solde-chart-ranges">
                    <button className="solde-range-btn"
                      onClick={() => setWindowStart(w => Math.max(0, w - 1))}
                      disabled={!canPrevR} style={{ opacity: canPrevR ? 1 : 0.3 }}>‹</button>
                    {visibleYearsR.map(y => (
                      <button key={y}
                        className={`solde-range-btn${selectedYear === String(y) ? ' active' : ''}`}
                        onClick={() => setSelectedYear(String(y))}>
                        {y}
                      </button>
                    ))}
                    <button className="solde-range-btn"
                      onClick={() => setWindowStart(w => Math.min(Math.max(0, availableYearsAsc.length - 3), w + 1))}
                      disabled={!canNextR} style={{ opacity: canNextR ? 1 : 0.3 }}>›</button>
                    <button
                      className={`solde-range-btn${!selectedYear ? ' active' : ''}`}
                      onClick={() => setSelectedYear('')}>
                      TOUT
                    </button>
                    <button type="button" className="icon-btn"
                      title={listFocused ? 'Réduire' : 'Agrandir'}
                      style={{ marginLeft: 4 }}
                      onClick={() => setListFocused(v => !v)}>
                      {listFocused ? (
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                          <polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/>
                          <line x1="10" y1="14" x2="3" y2="21"/><line x1="21" y1="3" x2="14" y2="10"/>
                        </svg>
                      ) : (
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                          <polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/>
                          <line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/>
                        </svg>
                      )}
                    </button>
                  </div>
                </div>
              </div>

              {allGridRows.length === 0 ? (
                <div style={{ padding: '24px 0', textAlign: 'center', color: 'var(--text-muted)', fontSize: 'var(--fs-sm)' }}>
                  Aucun remboursement{selectedYear ? ` en ${selectedYear}` : ''}.
                </div>
              ) : (
                <div style={{ overflowX: 'auto' }}>
                  <table className="tip-table">
                    <thead>
                      <tr>
                        <th className="tip-th-empty" style={{ minWidth: 200 }} />
                        <th className="tip-th-empty" style={{ minWidth: 80 }} />
                        <th className="tip-th-year" colSpan={12}>{displayYear}</th>
                        <th className="tip-th-empty" />
                      </tr>
                      <tr>
                        <th className="tip-th-name tip-th-name-amber">
                          <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                            Investissement
                            {multiHolder && (
                              <button onClick={() => toggleRembDetaille()}
                                title={rembDetaille ? 'Vue détaillée — cliquer pour consolider' : 'Vue consolidée — cliquer pour détailler par détenteur'}
                                style={{
                                  display: 'inline-flex', alignItems: 'center', gap: 3,
                                  background: 'rgba(255,255,255,0.15)', border: '1px solid rgba(255,255,255,0.3)',
                                  borderRadius: 4, padding: '2px 5px', cursor: 'pointer',
                                  fontSize: 10, fontWeight: 600, color: '#fff', letterSpacing: '.03em',
                                  lineHeight: 1.4, whiteSpace: 'nowrap',
                                }}>
                                {rembDetaille ? 'Consolidé' : 'Détaillé'}
                                <span style={{ display: 'inline-flex', transition: 'transform .2s', transform: rembDetaille ? 'rotate(180deg)' : 'rotate(0deg)' }}>
                                  <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6"/></svg>
                                </span>
                              </button>
                            )}
                          </span>
                        </th>
                        <th className="tip-th-name" style={{ minWidth: 'unset', position: 'static', fontSize: 'var(--fs-xs)', textAlign: 'left' }}>Statut</th>
                        {MOIS_LONG.map((m, i) => (
                          <th key={m} className={`tip-th-month${displayYear === currentYear && i === currentMonth - 1 ? ' tip-th-month-current' : ''}`}>{m}</th>
                        ))}
                        <th className="tip-th-total">Total</th>
                      </tr>
                    </thead>
                    <tbody>
                      {groups.map(([pid, { label, grid }]) => (
                        <Fragment key={pid ?? 'all'}>
                          {label && (
                            <tr>
                              <td colSpan={15} style={{ padding: '8px 10px 2px', fontSize: 'var(--fs-xs)', fontWeight: 600, color: 'var(--text-muted)', borderBottom: '1px solid var(--border)', letterSpacing: '.04em', textTransform: 'uppercase' }}>
                                {label}
                              </td>
                            </tr>
                          )}
                          {grid.map(({ inv, months }) => {
                            const rowTotal = months.reduce((s, v) => s + (v?.value ?? 0), 0);
                            return (
                              <tr key={inv.id} className="tip-row-plat" style={{ cursor: 'pointer' }}
                                onClick={() => navigate(`/investissements/${inv.id}`, { state: { from: { path: location.pathname, search: location.search, label: 'Plateformes' } } })}>
                                <td className="tip-td-name" style={{ whiteSpace: 'normal', maxWidth: '40ch', wordBreak: 'break-word' }}>
                                  {inv.nom_projet || '—'}
                                </td>
                                <td style={{ padding: '8px 10px', whiteSpace: 'nowrap', borderRight: '1px solid var(--border)' }}>
                                  <span className={`badge ${inv.statut}`}>{fmtStatut(inv.statut)}</span>
                                </td>
                {(() => {
                                  const firstNonNull = months.findIndex(v => v !== null);
                                  const lastNonNull  = months.reduce((last, v, i) => v !== null ? i : last, -1);
                                  return months.map((v, mi) => {
                                    const isAfter = inv.statut === 'rembourse' && (() => {
                                      const lastDate = lastRembDateMap[inv.id];
                                      if (!lastDate) return lastNonNull >= 0 && mi > lastNonNull;
                                      const lastYear = Number(lastDate.slice(0, 4));
                                      const lastMo   = Number(lastDate.slice(5, 7)) - 1;
                                      if (lastYear < displayYear) return true;
                                      if (lastYear === displayYear) return mi > lastMo;
                                      return false;
                                    })();
                                    const isBefore = firstNonNull > 0 && mi < firstNonNull;
                                    const isGrayed = (isAfter || isBefore) && !v;
                                    const curClass = displayYear === currentYear && mi === currentMonth - 1 ? ' tip-col-current' : '';
                                    if (isGrayed) return <td key={mi} className={`tip-td-closed${curClass}`} />;
                                    return (
                                      <td key={mi} className={colClass(mi, v?.projected)}>
                                        {v ? fmtEUR(v.value) : <span className="tip-dash">—</span>}
                                      </td>
                                    );
                                  });
                                })()}
                                <td className="tip-td-total">
                                  {rowTotal > 0 ? fmtEUR(rowTotal) : <span className="tip-dash">—</span>}
                                </td>
                              </tr>
                            );
                          })}
                        </Fragment>
                      ))}
                    </tbody>
                    <tfoot>
                      <tr className="tip-footer-total">
                        <td className="tip-td-name">Total</td>
                        <td />
                        {monthTotals.map((v, i) => (
                          <td key={i} className={colClass(i)}>
                            {v > 0 ? fmtEUR(v) : <span className="tip-dash">—</span>}
                          </td>
                        ))}
                        <td className="tip-td-total">
                          {grandTotal > 0 ? fmtEUR(grandTotal) : <span className="tip-dash">—</span>}
                        </td>
                      </tr>
                    </tfoot>
                  </table>
                </div>
              )}

              {/* ── Sélecteur Reçu / Projeté ── */}
              <div style={{ display: 'flex', alignItems: 'center', marginTop: 12 }}>
                <div style={{
                  display: 'inline-flex',
                  background: '#f0f0f0',
                  borderRadius: 8,
                  padding: 3,
                  gap: 2,
                  flexShrink: 0,
                }}>
                  {[
                    { key: 'actual',    label: 'Reçu',    active: rembShowActual,    toggle: () => setRembShowActual(v => !v) },
                    { key: 'projected', label: 'Projeté', active: rembShowProjected, toggle: () => setRembShowProjected(v => !v) },
                  ].map(btn => (
                    <button key={btn.key} onClick={() => btn.toggle()} style={{
                      border: 'none', cursor: 'pointer', padding: '5px 14px', borderRadius: 6,
                      fontSize: 'var(--fs-sm)',
                      fontWeight: btn.active ? 600 : 400,
                      background: btn.active ? '#ffffff' : 'transparent',
                      color:      btn.active ? '#1a1a2e' : '#9ca3af',
                      boxShadow:  btn.active ? '0 1px 3px rgba(0,0,0,0.13)' : 'none',
                      transition: 'all .15s', lineHeight: 1.4,
                    }}>{btn.label}</button>
                  ))}
                </div>
              </div>
            </div>
          </div>
        );
      })()}

            {/* ====== ONGLET DÉPÔTS / RETRAITS ====== */}
      {activeTab === 'depots-retraits' && (() => {
        const currentYear  = new Date().getFullYear();
        const currentMonth = new Date().getMonth() + 1;
        const displayYear  = selectedYear ? Number(selectedYear) : currentYear;
        const MOIS_LONG = ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'];

        const depotsByMonth   = Array(12).fill(0);
        const retraitsByMonth = Array(12).fill(0);
        const corrByMonth     = Array(12).fill(0);

        for (const d of allDepots) {
          if (!filteredPlatIds.has(d.plateforme_id)) continue;
          if (selectedYear && d.date_operation?.slice(0, 4) !== selectedYear) continue;
          const m = Number(d.date_operation.slice(5, 7)) - 1;
          if (d.type === 'depot') depotsByMonth[m]   += d.montant || 0;
          else                    retraitsByMonth[m] += d.montant || 0;
        }
        for (const co of allCorrections) {
          if (!filteredPlatIds.has(co.plateforme_id)) continue;
          if (selectedYear && co.date?.slice(0, 4) !== selectedYear) continue;
          const m = Number(co.date.slice(5, 7)) - 1;
          corrByMonth[m] += co.montant || 0;
        }

        const netByMonth    = depotsByMonth.map((v, i) => v - retraitsByMonth[i] + corrByMonth[i]);
        const totalDepots   = depotsByMonth.reduce((s, v) => s + v, 0);
        const totalRetraits = retraitsByMonth.reduce((s, v) => s + v, 0);
        const totalCorr     = corrByMonth.reduce((s, v) => s + v, 0);
        const totalNet      = totalDepots - totalRetraits + totalCorr;

        const visibleYearsDR = availableYearsAsc.length
          ? availableYearsAsc.slice(windowStart, windowStart + 3)
          : [currentYear];
        const canPrevDR = windowStart > 0;
        const canNextDR = windowStart + 3 < availableYearsAsc.length;

        return (
          <div style={{ padding: '0 24px' }}>
            <div className="solde-chart-wrap" style={{ padding: '24px 24px 16px', marginBottom: 24 }}>
              <div className="solde-chart-header" style={{ marginBottom: 16 }}>
                <div className="solde-chart-info">
                  <h3 style={{ margin: 0 }}>
                    Mouvements de trésorerie
                    <span style={{ marginLeft: 8, fontWeight: 400, color: 'var(--text-muted)', fontSize: '0.85em' }}>— {selectedYear || 'Toutes les années'}</span>
                  </h3>
                </div>
                <div className="solde-chart-controls">
                  <div className="solde-chart-ranges">
                    <button className="solde-range-btn"
                      onClick={() => setWindowStart(w => Math.max(0, w - 1))}
                      disabled={!canPrevDR} style={{ opacity: canPrevDR ? 1 : 0.3 }}>‹</button>
                    {visibleYearsDR.map(y => (
                      <button key={y}
                        className={`solde-range-btn${selectedYear === String(y) ? ' active' : ''}`}
                        onClick={() => setSelectedYear(String(y))}>
                        {y}
                      </button>
                    ))}
                    <button className="solde-range-btn"
                      onClick={() => setWindowStart(w => Math.min(Math.max(0, availableYearsAsc.length - 3), w + 1))}
                      disabled={!canNextDR} style={{ opacity: canNextDR ? 1 : 0.3 }}>›</button>
                    <button
                      className={`solde-range-btn${!selectedYear ? ' active' : ''}`}
                      onClick={() => setSelectedYear('')}>
                      TOUT
                    </button>
                    <button type="button" className="icon-btn"
                      title={listFocused ? 'Réduire' : 'Agrandir'}
                      style={{ marginLeft: 4 }}
                      onClick={() => setListFocused(v => !v)}>
                      {listFocused ? (
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                          <polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/>
                          <line x1="10" y1="14" x2="3" y2="21"/><line x1="21" y1="3" x2="14" y2="10"/>
                        </svg>
                      ) : (
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                          <polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/>
                          <line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/>
                        </svg>
                      )}
                    </button>
                  </div>
                </div>
              </div>
              {/* Données par détenteur en mode détaillé */}
              {(() => {
                // Construire un map platId → { detenteurNom, depotsByM, retraitsByM, corrByM }
                const multiHolder = filteredPlatIds.size > 1;
                const showDetaille = drDetaille && multiHolder;

                // Map platId → détenteur nom (depuis plats)
                const detenteurByPlatId = {};
                for (const pid of filteredPlatIds) {
                  const p = plats.find(pl => pl.id === pid);
                  detenteurByPlatId[pid] = p?.investisseur_nom || String(pid);
                }

                // Construire les données par platId
                const byPlatId = {};
                for (const pid of filteredPlatIds) {
                  byPlatId[pid] = { depots: Array(12).fill(0), retraits: Array(12).fill(0), corr: Array(12).fill(0) };
                }
                for (const d of allDepots) {
                  if (!filteredPlatIds.has(d.plateforme_id)) continue;
                  if (selectedYear && d.date_operation?.slice(0, 4) !== selectedYear) continue;
                  const m = Number(d.date_operation.slice(5, 7)) - 1;
                  if (d.type === 'depot') byPlatId[d.plateforme_id].depots[m]   += d.montant || 0;
                  else                    byPlatId[d.plateforme_id].retraits[m] += d.montant || 0;
                }
                for (const co of allCorrections) {
                  if (!filteredPlatIds.has(co.plateforme_id)) continue;
                  if (selectedYear && co.date?.slice(0, 4) !== selectedYear) continue;
                  const m = Number(co.date.slice(5, 7)) - 1;
                  byPlatId[co.plateforme_id].corr[m] += co.montant || 0;
                }

                // Helpers navigation
                const makeGoTo = (type, month, platId) => () => {
                  const p = new URLSearchParams({ tab: 'mouvements', type, year: String(displayYear) });
                  if (month !== null) p.set('month', String(month + 1).padStart(2, '0'));
                  if (platId != null) p.set('plat_ids', String(platId));
                  else if (filteredPlatIds.size > 0) p.set('plat_ids', [...filteredPlatIds].join(','));
                  navigate('/depots-retraits?' + p.toString());
                };

                // Rendu d'un groupe de 3 lignes (depot/retrait/corr) pour un platId donné (null = consolidé)
                const renderGroup = (pid, key) => {
                  const data = pid != null ? byPlatId[pid] : {
                    depots: depotsByMonth, retraits: retraitsByMonth, corr: corrByMonth
                  };
                  const label = pid != null ? detenteurByPlatId[pid] : null;
                  const tDep = data.depots.reduce((s, v) => s + v, 0);
                  const tRet = data.retraits.reduce((s, v) => s + v, 0);
                  const tCor = data.corr.reduce((s, v) => s + v, 0);
                  const hasCorr = data.corr.some(v => v !== 0);
                  const colClass = (i) => `tip-td-num${displayYear === currentYear && i === currentMonth - 1 ? ' tip-col-current' : ''}`;
                  return (
                    <Fragment key={key}>
                      {label && (
                        <tr>
                          <td colSpan={14} style={{ padding: '8px 10px 2px', fontSize: 'var(--fs-xs)', fontWeight: 600, color: 'var(--text-muted)', borderBottom: '1px solid var(--border)', letterSpacing: '.04em', textTransform: 'uppercase' }}>
                            {label}
                          </td>
                        </tr>
                      )}
                      <tr className="tip-row-plat">
                        <td className="tip-td-name" style={{ fontWeight: 600 }}>Dépôts</td>
                        {data.depots.map((v, i) => (
                          <td key={i} className={`${colClass(i)}${v > 0 ? ' tip-td-link' : ''}`}
                            onClick={v > 0 ? makeGoTo('depot', i, pid) : undefined}
                            style={v > 0 ? { cursor: 'pointer' } : undefined}>
                            {v > 0 ? fmtEUR(v) : <span className="tip-dash">—</span>}
                          </td>
                        ))}
                        <td className={`tip-td-total${tDep > 0 ? ' tip-td-link' : ''}`}
                          onClick={tDep > 0 ? makeGoTo('depot', null, pid) : undefined}
                          style={tDep > 0 ? { cursor: 'pointer' } : undefined}>
                          {tDep > 0 ? fmtEUR(tDep) : <span className="tip-dash">—</span>}
                        </td>
                      </tr>
                      <tr className="tip-row-plat">
                        <td className="tip-td-name" style={{ fontWeight: 600 }}>Retraits</td>
                        {data.retraits.map((v, i) => (
                          <td key={i} className={`${colClass(i)}${v > 0 ? ' tip-td-link' : ''}`}
                            onClick={v > 0 ? makeGoTo('retrait', i, pid) : undefined}
                            style={v > 0 ? { cursor: 'pointer' } : undefined}>
                            {v > 0 ? <>−{fmtEUR(v)}</> : <span className="tip-dash">—</span>}
                          </td>
                        ))}
                        <td className={`tip-td-total${tRet > 0 ? ' tip-td-link' : ''}`}
                          onClick={tRet > 0 ? makeGoTo('retrait', null, pid) : undefined}
                          style={tRet > 0 ? { cursor: 'pointer' } : undefined}>
                          {tRet > 0 ? <>−{fmtEUR(tRet)}</> : <span className="tip-dash">—</span>}
                        </td>
                      </tr>
                      {hasCorr && (
                        <tr className="tip-row-plat">
                          <td className="tip-td-name" style={{ fontWeight: 600 }}>Corrections</td>
                          {data.corr.map((v, i) => (
                            <td key={i} className={`${colClass(i)}${v !== 0 ? ' tip-td-link' : ''}`}
                              onClick={v !== 0 ? makeGoTo('correction', i, pid) : undefined}
                              style={v !== 0 ? { cursor: 'pointer' } : undefined}>
                              {v !== 0 ? <>{v < 0 ? '−' : '+'}{fmtEUR(Math.abs(v))}</> : <span className="tip-dash">—</span>}
                            </td>
                          ))}
                          <td className={`tip-td-total${tCor !== 0 ? ' tip-td-link' : ''}`}
                            onClick={tCor !== 0 ? makeGoTo('correction', null, pid) : undefined}
                            style={tCor !== 0 ? { cursor: 'pointer' } : undefined}>
                            {tCor !== 0 ? <>{tCor < 0 ? '−' : '+'}{fmtEUR(Math.abs(tCor))}</> : <span className="tip-dash">—</span>}
                          </td>
                        </tr>
                      )}
                    </Fragment>
                  );
                };

                return (
                  <div style={{ overflowX: 'auto' }}>
                    <table className="tip-table">
                      <thead>
                        <tr>
                          <th className="tip-th-empty" style={{ minWidth: 160 }} />
                          <th className="tip-th-year" colSpan={12}>{displayYear}</th>
                          <th className="tip-th-empty" />
                        </tr>
                        <tr>
                          <th className="tip-th-name tip-th-name-amber">
                            <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                              Mouvement
                              {multiHolder && (
                                <button onClick={() => toggleDrDetaille()}
                                  title={drDetaille ? 'Vue détaillée — cliquer pour consolider' : 'Vue consolidée — cliquer pour détailler par détenteur'}
                                  style={{
                                    display: 'inline-flex', alignItems: 'center', gap: 3,
                                    background: 'rgba(255,255,255,0.15)', border: '1px solid rgba(255,255,255,0.3)',
                                    borderRadius: 4, padding: '2px 5px', cursor: 'pointer',
                                    fontSize: 10, fontWeight: 600, color: '#fff', letterSpacing: '.03em',
                                    lineHeight: 1.4, whiteSpace: 'nowrap',
                                  }}>
                                  {drDetaille ? 'Consolidé' : 'Détaillé'}
                                  <span style={{ display: 'inline-flex', transition: 'transform .2s', transform: drDetaille ? 'rotate(180deg)' : 'rotate(0deg)' }}>
                                    <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6"/></svg>
                                  </span>
                                </button>
                              )}
                            </span>
                          </th>
                          {MOIS_LONG.map((m, i) => (
                            <th key={m} className={`tip-th-month${displayYear === currentYear && i === currentMonth - 1 ? ' tip-th-month-current' : ''}`}>{m}</th>
                          ))}
                          <th className="tip-th-total">Total</th>
                        </tr>
                      </thead>
                      <tbody>
                        {showDetaille
                          ? [...filteredPlatIds].map(pid => renderGroup(pid, pid))
                          : renderGroup(null, 'consolidated')
                        }
                      </tbody>
                      <tfoot>
                        <tr className="tip-footer-total">
                          <td className="tip-td-name">Net</td>
                          {netByMonth.map((v, i) => (
                            <td key={i} className={`tip-td-num${displayYear === currentYear && i === currentMonth - 1 ? ' tip-col-current' : ''}`}>
                              {v !== 0 ? fmtEUR(v) : <span className="tip-dash">—</span>}
                            </td>
                          ))}
                          <td className="tip-td-total">
                            {totalNet !== 0 ? fmtEUR(totalNet) : <span className="tip-dash">—</span>}
                          </td>
                        </tr>
                      </tfoot>
                    </table>
                  </div>
                );
              })()}

              {/* Suivi des objectifs de versement — toujours sur le portefeuille entier,
                  indépendamment du filtre plateforme de cette page (cf. décision produit). */}
              <SuiviObjectifs
                rows={allDepots}
                investisseurs={investisseurs}
                scopeInvestisseurIds={activeView === 'all' ? investisseurs.map(i => i.id) : [activeId]}
              />
            </div>
          </div>
        );
      })()}

      {/* ====== ONGLET VISION MENSUELLE ====== */}
      {activeTab === 'capital-investi' && (() => {
        const currentYear = new Date().getFullYear();
        const visibleYears = availableYearsAsc.length
          ? availableYearsAsc.slice(windowStart, windowStart + 3)
          : [currentYear];
        const canPrev = windowStart > 0;
        const canNext = windowStart + 3 < availableYearsAsc.length;
        return (
          <div style={{ padding: '0 24px' }}>
            <div className="solde-chart-wrap" style={{ padding: '24px 24px 16px', marginBottom: 24 }}>
              <div className="solde-chart-header">
                <div className="solde-chart-info">
                  <h3 style={{ margin: 0 }}>
                    Capital investi par investissement
                    <span style={{ marginLeft: 8, fontWeight: 400, color: 'var(--text-muted)', fontSize: '0.85em' }}>— {selectedYear || 'Toutes les années'}</span>
                  </h3>
                </div>
                <div className="solde-chart-controls">
                  <div className="solde-chart-ranges">
                    <button className="solde-range-btn"
                      onClick={() => setWindowStart(w => Math.max(0, w - 1))}
                      disabled={!canPrev} style={{ opacity: canPrev ? 1 : 0.3 }}>‹</button>
                    {visibleYears.map(y => (
                      <button key={y}
                        className={`solde-range-btn${selectedYear === String(y) ? ' active' : ''}`}
                        onClick={() => setSelectedYear(String(y))}>
                        {y}
                      </button>
                    ))}
                    <button className="solde-range-btn"
                      onClick={() => setWindowStart(w => Math.min(Math.max(0, availableYearsAsc.length - 3), w + 1))}
                      disabled={!canNext} style={{ opacity: canNext ? 1 : 0.3 }}>›</button>
                    <button
                      className={`solde-range-btn${!selectedYear ? ' active' : ''}`}
                      onClick={() => setSelectedYear('')}>
                      TOUT
                    </button>
                    <button type="button" className="icon-btn"
                      title={listFocused ? 'Réduire' : 'Agrandir'}
                      style={{ marginLeft: 4 }}
                      onClick={() => setListFocused(v => !v)}>
                      {listFocused ? (
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                          <polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/>
                          <line x1="10" y1="14" x2="3" y2="21"/><line x1="21" y1="3" x2="14" y2="10"/>
                        </svg>
                      ) : (
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                          <polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/>
                          <line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/>
                        </svg>
                      )}
                    </button>
                  </div>
                </div>
              </div>
              <InvMensuelTable
                rows={filteredRows}
                allRembs={allRembs}
                allReinvests={allReinvests}
                year={selectedYear}
                originFrom={{ path: location.pathname, search: location.search, label: 'Plateformes' }}
              />
            </div>
          </div>
        );
      })()}

      {/* ====== ONGLET INVESTISSEMENTS ====== */}
      {activeTab === 'investissements' && (
        <div style={{ padding: '0 24px' }}>
          <div className="card" style={{ marginBottom: 16 }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
              <h3 style={{ margin: 0 }}>
                Investissements
                {selectedYear && <span style={{ marginLeft: 8, fontWeight: 400, color: 'var(--text-muted)', fontSize: '0.85em' }}>— {selectedYear}</span>}
              </h3>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span style={{ fontSize: 'var(--fs-sm)', color: 'var(--text-muted)' }}>
                  {chartRows.length} investissement{chartRows.length !== 1 ? 's' : ''}
                </span>
                <button type="button" className="icon-btn"
                  title={listFocused ? 'Réduire' : 'Agrandir'}
                  onClick={() => setListFocused(v => !v)}>
                  {listFocused ? (
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                      <polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/>
                      <line x1="10" y1="14" x2="3" y2="21"/><line x1="21" y1="3" x2="14" y2="10"/>
                    </svg>
                  ) : (
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                      <polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/>
                      <line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/>
                    </svg>
                  )}
                </button>
              </div>
            </div>

            {!chartRows.length ? (
              <div className="text-muted" style={{ padding: '24px 0', textAlign: 'center' }}>
                {loading ? 'Chargement…' : 'Aucun investissement'}
              </div>
            ) : (
              <>
              <table>
                <thead>
                  <tr>
                    <th>Projet</th>
                    {multiDetenteur && <th>Détenteur</th>}
                    <th className="num">Date de souscription</th>
                    <th className="num">Date cible</th>
                    <th className="num">Montant</th>
                    <th className="num">Capital restant</th>
                    <th className="num">Intérêts ({netMode ? 'Net' : 'Brut'})</th>
                    <th>Statut</th>
                  </tr>
                </thead>
                <tbody>
                  {pagedChartRows.map(r => {
                      const capInv     = r.montant_investi + (reinvestCumulParInv[r.id] || 0);
                      const capRemb    = capRembParInv[r.id] || 0;
                      const capRestant = Math.max(0, capInv - capRemb);
                      const interets   = netMode
                        ? (rembParInv[r.id]?.interets_nets  || 0)
                        : (rembParInv[r.id]?.interets_bruts || 0);
                      return (
                        <tr key={r.id} style={{ cursor: 'pointer' }}
                          onClick={() => navigate(`/investissements/${r.id}`, { state: { from: { path: location.pathname, search: location.search, label: 'Plateformes' } } })}>
                          <td style={{ fontWeight: 500 }}>{r.nom_projet}</td>
                          {multiDetenteur && <td className="text-muted" style={{ fontSize: 'var(--fs-sm)' }}>{(() => { const inv = investisseurs.find(i => i.id === r.investisseur_id); return inv ? memberLabel(inv) : '—'; })()}</td>}
                          <td className="num" style={{ fontSize: 'var(--fs-sm)', color: 'var(--text-muted)' }}>{fmtDate(r.date_souscription)}</td>
                          <td className="num" style={{ fontSize: 'var(--fs-sm)', color: 'var(--text-muted)' }}>{fmtDate(r.date_cible)}</td>
                          <td className="num">{fmtEUR(r.montant_investi)}</td>
                          <td className="num">{capRestant > 0 ? fmtEUR(capRestant) : <span className="text-muted">—</span>}</td>
                          <td className="num">{interets > 0 ? fmtEUR(interets) : <span className="text-muted">—</span>}</td>
                          <td><span className={`badge ${r.statut}`}>{fmtStatut(r.statut)}</span></td>
                        </tr>
                      );
                    })}
                </tbody>
              </table>
              <Pagination
                page={platInvPage} setPage={setPlatInvPage}
                pageSize={platInvPageSize} setPageSize={setPlatInvPageSize}
                totalPages={platInvTotalPages} totalItems={platInvTotalItems}
                PAGE_SIZES={platInvPageSizes}
              />
              </>
            )}
          </div>
        </div>
      )}
    </>
  );
}
