import { useEffect, useMemo, useRef, useState } from 'react';
import { usePagination } from '../hooks/usePagination.js';
import Pagination from '../components/Pagination.jsx';
import PageIcon from '../components/PageIcon.jsx';
import EmptyState from '../components/EmptyState.jsx';
import { useLocation, useNavigate } from 'react-router-dom';
import { api } from '../api.js';
import { useInvestisseur } from '../context/InvestisseurContext.jsx';
import { useUi } from '../context/UiContext.jsx';
import Modal from '../components/Modal.jsx';
import ConfirmModal from '../components/ConfirmModal.jsx';
import InteretsChart from '../components/InteretsChart.jsx';
import InteretsDistributionChart from '../components/InteretsDistributionChart.jsx';
import TableauInteretsPlateforme from '../components/TableauInteretsPlateforme.jsx';
import DrillCellPanel from '../components/DrillCellPanel.jsx';
import { InteretsChartProvider } from '../context/InteretsChartContext.jsx';
import { fmtEUR, fmtDate, today, memberLabel } from '../utils/format.js';
import * as XLSX from 'xlsx';

const MOIS_FR = ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'];

/* ── Indicateur de progression ── */
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>
  );
}



const BONUS_VALUES = ['BONUS_PARRAINAGE', 'BONUS_PLATEFORME'];
const ICONS_BASE = '/api/icons-files/';
const BONUS_TYPE_MAP = { BONUS_PARRAINAGE: 'bonus_parrainage', BONUS_PLATEFORME: 'bonus_plateforme' };

const empty = {
  investissement_id: '', date_remb: today(),
  capital: 0, cashback: 0,
  interets_bruts_avant_local: 0,
  taxe_locale: 0,
  interets_bruts: 0, prelev_sociaux: 0,
  prelev_forfaitaire: 0,
  statut: 'paye', notes: '',
  methode_remboursement: 'portefeuille',
  compte_id: '',
  // champs bonus
  bonus_plateforme_id: '',
  bonus_investisseur_id: '',
};

/* ── Export helpers ─────────────────────────────────────────── */
function dlBlob(content, filename, type) {
  const blob = new Blob([content], { type });
  const url  = URL.createObjectURL(blob);
  const a    = document.createElement('a');
  a.href = url; a.download = filename; a.click();
  URL.revokeObjectURL(url);
}

function rembToCSV(rows) {
  const BOM = '﻿'; const sep = ';';
  const q = v => `"${String(v ?? '').replace(/"/g, '""')}"`;
  const headers = ['Date','Plateforme','Projet','Capital (€)','Cashback (€)','Intérêts bruts (€)','Prélèv. sociaux (€)','Impôt revenu (€)','Intérêts nets (€)','Net reçu (€)'];
  const data = rows.map(r => [
    r.date_remb, r.plateforme_nom||'', r.nom_projet||'',
    String(r.capital||0).replace('.',','), String(r.cashback||0).replace('.',','),
    String(r.interets_bruts||0).replace('.',','), String(r.prelev_sociaux||0).replace('.',','),
    String(r.prelev_forfaitaire||0).replace('.',','), String(r.interets_nets||0).replace('.',','),
    String(r.net_recu||0).replace('.',','),
  ]);
  return BOM + [headers, ...data].map(r => r.map(q).join(sep)).join('\r\n');
}

function rembToXLS(rows) {
  const data = rows.map(r => ({
    'Date':                  r.date_remb,
    'Plateforme':            r.plateforme_nom || '',
    'Projet':                r.nom_projet || '',
    'Capital (€)':           r.capital || 0,
    'Cashback (€)':          r.cashback || 0,
    'Intérêts bruts (€)':    r.interets_bruts || 0,
    'Prélèv. sociaux (€)':   r.prelev_sociaux || 0,
    'Impôt revenu (€)':      r.prelev_forfaitaire || 0,
    'Intérêts nets (€)':     r.interets_nets || 0,
    'Net reçu (€)':          r.net_recu || 0,
  }));
  const ws = XLSX.utils.json_to_sheet(data);
  const wb = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(wb, ws, 'Remboursements');
  return XLSX.write(wb, { type: 'array', bookType: 'xlsx' });
}
function rembToJSON(rows) {
  return JSON.stringify(rows.map(r => ({
    date_remb: r.date_remb, plateforme: r.plateforme_nom||'', projet: r.nom_projet||'',
    capital: r.capital||0, cashback: r.cashback||0,
    interets_bruts: r.interets_bruts||0, prelev_sociaux: r.prelev_sociaux||0,
    prelev_forfaitaire: r.prelev_forfaitaire||0, interets_nets: r.interets_nets||0,
    net_recu: r.net_recu||0,
  })), null, 2);
}

/* ── ExportDropdown ─────────────────────────────────────────── */
function ExportDropdown({ disabled, onCSV, onXLS, onJSON }) {
  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 choose = fn => { setOpen(false); fn(); };
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button type="button" className="icon-btn" disabled={disabled}
        onClick={() => setOpen(o => !o)} title="Exporter">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>
        </svg>
      </button>
      {open && (
        <div className="export-dropdown" role="menu">
          <button role="menuitem" onClick={() => choose(onCSV)}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/>
              <line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="16" y2="17"/>
            </svg>
            <span><strong>Format CSV</strong><small>Compatible Excel, LibreOffice</small></span>
          </button>
          <button role="menuitem" onClick={() => choose(onXLS)}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M9 13l2 2 4-4"/>
            </svg>
            <span><strong>Format Excel</strong><small>Fichier .xlsx Microsoft Excel</small></span>
          </button>
          <button role="menuitem" onClick={() => choose(onJSON)}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/>
              <path d="M8 13h1.5a1 1 0 0 1 1 1v1a1 1 0 0 0 1 1 1 1 0 0 0-1 1v1a1 1 0 0 1-1 1H8"/>
              <path d="M16 13h-1.5a1 1 0 0 0-1 1v1a1 1 0 0 1-1 1 1 1 0 0 1 1 1v1a1 1 0 0 0 1 1H16"/>
            </svg>
            <span><strong>Format JSON</strong><small>Réimportable, structuré</small></span>
          </button>
        </div>
      )}
    </div>
  );
}

/* ── Composant principal ─────────────────────────────────────── */
export default function Remboursements() {
  const { activeId, activeView, investisseurs } = useInvestisseur();
  const { displayMode } = useUi();
  const { search }   = useLocation();
  const navigate     = useNavigate();

  /* netMode dérivé du contexte global */
  const netMode = displayMode === 'net';

  /* ── State ── */
  const [allRows,         setAllRows]         = useState([]);
  const [corrections,     setCorrections]     = useState([]);
  const [investissements, setInvestissements] = useState([]);
  const [plateformes,     setPlateformes]     = useState([]);
  const [platLoaded,      setPlatLoaded]      = useState(false);
  const [pfuRates,        setPfuRates]        = useState([]);
  const [loading,         setLoading]         = useState(false);

  /* Charts / filtres visuels */
  const [filterPlatId, setFilterPlatId] = useState('');    // filtre depuis onglet Plateformes

  /* Onglets */
  const [activeTab, setActiveTab] = useState('plateformes');
  const [listFocused, setListFocused] = useState(false);

  /* ── Drill-down cellule vision mensuelle ── */
  const [drillCell,       setDrillCell]       = useState(null);
  const [drillRefreshKey, setDrillRefreshKey] = useState(0);
  const drillPanelRef = useRef(null);
  const tipTableRef   = useRef(null);

  /* ── Navigation retour Dashboard ── */
  const autoOpenRef         = useRef(false);   // garantit l'ouverture auto une seule fois
  const backToDashboardRef  = useRef(null);    // URL de retour quand from=dashboard

  const handleCellClick = (cellInfo) => {
    setDrillCell(prev => (prev?.key === cellInfo.key ? null : cellInfo));
  };

  /* Scroll automatique à l'ouverture/fermeture du panneau */
  useEffect(() => {
    if (drillCell) {
      // Petit délai pour laisser React rendre le panneau avant de scroller
      setTimeout(() => {
        drillPanelRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }, 50);
    } else {
      setTimeout(() => {
        tipTableRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }, 50);
    }
  }, [drillCell]);

  /* Filtre du tableau Remboursements */
  const [tableFilter, setTableFilter] = useState({ plateforme_id: '', investissement_id: '', year: '', month: '', type: '' });

  /* Filtre année du tableau Plateformes */
  const [rembPlatYear, setRembPlatYear] = useState(String(new Date().getFullYear()));

  /* Modal */
  const [modalOpen,        setModalOpen]        = useState(false);
  const [editingId,        setEditingId]        = useState(null);
  const [form,             setForm]             = useState(empty);
  const [err,              setErr]              = useState(null);
  const [confirmingDelete, setConfirmingDelete] = useState(false);
  const [corrDeleteConfirm, setCorrDeleteConfirm] = useState(null);
  const [comptesInvestisseur, setComptesInvestisseur] = useState([]);
  const [libIcons, setLibIcons] = useState({});
  const [filterPortefeuille,   setFilterPortefeuille]   = useState(true);
  const [filterCompteCourant,  setFilterCompteCourant]  = useState(true);
  const [openMenu, setOpenMenu] = useState(null);

  /* Projections échéances */
  const [selectedSimul, setSelectedSimul] = useState('');
  const [echeances,     setEcheances]     = useState([]);
  const [simulBusy,     setSimulBusy]     = useState(false);
  const [simulMsg,      setSimulMsg]      = useState(null);

  /* ── Chargement ── */
  const load = async () => {
    if (!activeId && activeView !== 'all') return;
    setLoading(true);
    setAllRows([]);        // vide les données résiduelles
    setInvestissements([]); // idem pour la liste projections
    setSelectedSimul('');   // reset sélection projection
    try {
      const scopeParams = activeView === 'all' ? { scope: 'all' } : {};
      const [r, inv, corr] = await Promise.all([
        api.get('/remboursements', scopeParams),
        api.get('/investissements', scopeParams),
        api.get('/corrections', scopeParams).catch(() => []),
      ]);
      setAllRows(r); setInvestissements(inv); setCorrections(corr);
    } finally {
      setLoading(false);
      setDrillRefreshKey(k => k + 1);
    }
  };

  useEffect(() => {
    api.get('/pfu').then(setPfuRates).catch(() => {});
    api.get('/plateformes').then(d => { setPlateformes(d); setPlatLoaded(true); }).catch(() => { setPlatLoaded(true); });
    api.get('/icons').then(rows => { const m = {}; rows.forEach(r => { m[r.name] = r.filename; }); setLibIcons(m); }).catch(() => {});
  }, []);

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

  // Ferme tous les menus contextuels au scroll
  useEffect(() => {
    const closeAll = () => {
      setOpenMenu(null);
    };
    window.addEventListener('scroll', closeAll, true);
    return () => window.removeEventListener('scroll', closeAll, true);
  }, []);

  /* Auto-sélection du premier investissement dès le chargement */
  useEffect(() => {
    if (selectedSimul || !investissements.length) return;
    setSelectedSimul(String(investissements[0].id));
  }, [investissements]); /* eslint-disable-next-line */

  useEffect(() => {
    if (!selectedSimul) { setEcheances([]); return; }
    api.get('/simul', { investissement_id: selectedSimul }).then(setEcheances).catch(() => {});
  }, [selectedSimul]);

  const generateSimul = async () => {
    if (!selectedSimul) return;
    setSimulBusy(true); setSimulMsg(null);
    try {
      const r = await api.post('/simul/generate', { investissement_id: Number(selectedSimul), replace: true });
      setSimulMsg(`✔ ${r.inserted} échéances générées.`);
      const e = await api.get('/simul', { investissement_id: selectedSimul });
      setEcheances(e);
    } catch (e) { setSimulMsg(`✗ ${e.message}`); }
    finally { setSimulBusy(false); }
  };

  /* ── Données pour graphiques et KPI : filtrées par plateforme ET année ── */
  const chartRows = useMemo(() =>
    allRows.filter(r => {
      if (filterPlatId  && String(r.plateforme_id) !== filterPlatId)         return false;
      if (rembPlatYear  && r.date_remb.slice(0, 4) !== rembPlatYear)         return false;
      return true;
    }),
    [allRows, filterPlatId, rembPlatYear]
  );

  /* ── Corrections filtrées (même scope plateforme + année) ── */
  const filteredCorrections = useMemo(() =>
    corrections.filter(c => {
      if (filterPlatId && String(c.plateforme_id) !== filterPlatId) return false;
      if (rembPlatYear && c.date.slice(0, 4) !== rembPlatYear)      return false;
      return true;
    }),
    [corrections, filterPlatId, rembPlatYear]
  );

  /* ── KPIs (calculés sur chartRows + corrections) ── */
  const totals = useMemo(() => {
    const base = chartRows.reduce((acc, r) => {
      acc.capital       += r.capital        || 0;
      acc.cashback      += r.cashback       || 0;
      acc.interets      += r.interets_bruts || 0;
      acc.interets_nets += r.interets_nets  || 0;
      return acc;
    }, { capital: 0, cashback: 0, interets: 0, interets_nets: 0 });
    // Les corrections s'ajoutent uniquement au net (brut = 0)
    base.interets_nets += filteredCorrections.reduce((s, c) => s + c.montant, 0);
    return base;
  }, [chartRows, filteredCorrections]);

  /* ── Totaux KPI année N-1 (pour TrendBadge) ── */
  const rembPrevYear = String(Number(rembPlatYear || new Date().getFullYear()) - 1);
  const prevTotals = useMemo(() => {
    const prevRows = allRows.filter(r => {
      if (filterPlatId && String(r.plateforme_id) !== filterPlatId) return false;
      return r.date_remb.slice(0, 4) === rembPrevYear;
    });
    const base = prevRows.reduce((acc, r) => {
      acc.capital       += r.capital        || 0;
      acc.cashback      += r.cashback       || 0;
      acc.interets      += r.interets_bruts || 0;
      acc.interets_nets += r.interets_nets  || 0;
      return acc;
    }, { capital: 0, cashback: 0, interets: 0, interets_nets: 0 });
    const prevCorr = corrections.filter(c => {
      if (filterPlatId && String(c.plateforme_id) !== filterPlatId) return false;
      return c.date.slice(0, 4) === rembPrevYear;
    });
    base.interets_nets += prevCorr.reduce((s, c) => s + c.montant, 0);
    return base;
  }, [allRows, corrections, filterPlatId, rembPrevYear]);

  /* ── Données par plateforme (onglet Plateformes) ── */
  const byPlatform = useMemo(() => {
    const src = rembPlatYear
      ? allRows.filter(r => r.date_remb.slice(0, 4) === rembPlatYear)
      : allRows;
    const map = {};
    for (const r of src) {
      const key = String(r.plateforme_id);
      if (!map[key]) map[key] = {
        plateforme_id: r.plateforme_id, nom: r.plateforme_nom,
        detenteur_nom: r.plateforme_detenteur_nom || null,
        capital: 0, cashback: 0, interets_bruts: 0, interets_nets: 0, net_recu: 0, count: 0,
      };
      map[key].capital        += r.capital        || 0;
      map[key].cashback       += r.cashback       || 0;
      map[key].interets_bruts += r.interets_bruts || 0;
      map[key].interets_nets  += r.interets_nets  || 0;
      map[key].net_recu       += r.net_recu       || 0;
      map[key].count++;
    }
    return Object.values(map).sort((a, b) => b.interets_nets - a.interets_nets);
  }, [allRows, rembPlatYear]);

  const totalInterets = byPlatform.reduce((s, p) => s + (netMode ? p.interets_nets : p.interets_bruts), 0);

  const byPlatformTotals = useMemo(() =>
    byPlatform.reduce((acc, p) => {
      acc.capital        += p.capital;
      acc.cashback       += p.cashback;
      acc.interets_bruts += p.interets_bruts;
      acc.interets_nets  += p.interets_nets;
      acc.net_recu       += p.net_recu;
      acc.count          += p.count;
      return acc;
    }, { capital: 0, cashback: 0, interets_bruts: 0, interets_nets: 0, net_recu: 0, count: 0 }),
    [byPlatform]
  );

  /* ── Tableau remboursements : filtrage client-side ── */
  const tableRows = useMemo(() => {
    // Remboursements filtrés
    const remb = allRows.filter(r => {
      if (tableFilter.plateforme_id && String(r.plateforme_id) !== String(tableFilter.plateforme_id)) return false;
      // Filtre porte-monnaie / compte-courant
      if (!filterPortefeuille && !filterCompteCourant) return false;
      if (!filterPortefeuille && (r.methode_remboursement === 'portefeuille' || !r.methode_remboursement)) return false;
      if (!filterCompteCourant && r.methode_remboursement === 'compte_courant') return false;
      // Filtre type : les corrections n'ont pas de type remboursement
      if (tableFilter.type && tableFilter.type !== 'correction_solde' && r.type !== tableFilter.type) return false;
      if (tableFilter.type === 'correction_solde') return false; // géré séparément
      // Filtre projet
      const isBonusTypeFilter = tableFilter.type === 'bonus_parrainage' || tableFilter.type === 'bonus_plateforme';
      if (!isBonusTypeFilter && tableFilter.investissement_id) {
        const isBonus = r.type === 'bonus_parrainage' || r.type === 'bonus_plateforme';
        if (isBonus) return false;
        if (String(r.investissement_id) !== String(tableFilter.investissement_id)) return false;
      }
      const [y, m] = r.date_remb.split('-');
      if (tableFilter.year  && y !== tableFilter.year)                   return false;
      if (tableFilter.month && m !== tableFilter.month.padStart(2, '0')) return false;
      return true;
    });

    // Corrections filtrées (normalisées pour l'affichage)
    const showCorrections = filterPortefeuille && (!tableFilter.type || tableFilter.type === 'correction_solde');
    const corr = showCorrections ? corrections.filter(c => {
      if (tableFilter.plateforme_id && String(c.plateforme_id) !== String(tableFilter.plateforme_id)) return false;
      const [y, m] = c.date.split('-');
      if (tableFilter.year  && y !== tableFilter.year)                   return false;
      if (tableFilter.month && m !== tableFilter.month.padStart(2, '0')) return false;
      return true;
    }).map(c => ({
      ...c,
      _is_correction: true,
      date_remb: c.date,
      type: 'correction_solde',
      nom_projet: c.notes || 'Correction de solde',
      capital: 0, cashback: 0, interets_bruts: 0, prelev_sociaux: 0,
      prelev_forfaitaire: 0, interets_nets: c.montant, net_recu: c.montant,
      statut: 'paye',
    })) : [];

    return [...remb, ...corr].sort((a, b) =>
      (b.date_remb || '').localeCompare(a.date_remb || '')
    );
  }, [allRows, corrections, tableFilter, filterPortefeuille, filterCompteCourant]);

  /* ── Pagination remboursements ── */
  const {
    pagedItems: pagedTableRows, page: rembPage, setPage: setRembPage,
    pageSize: rembPageSize, setPageSize: setRembPageSize,
    totalPages: rembTotalPages, totalItems: rembTotalItems, PAGE_SIZES,
  } = usePagination(tableRows, 'cl_pagesize_remb', [tableFilter]);

  const years = useMemo(() =>
    [...new Set(allRows.map(r => r.date_remb.slice(0, 4)))].sort().reverse(),
    [allRows]
  );

  /* ── Investissements éligibles ── */
  const investissementsActifs = investissements.filter(i => i.statut !== 'rembourse');

  /* ── Ouverture auto depuis le bouton global "Nouveau remboursement" ── */
  useEffect(() => {
    if (new URLSearchParams(search).get('new') !== '1') return;
    navigate('/remboursements', { replace: true });
    setEditingId(null);
    setForm({ ...empty, investissement_id: '' });
    setErr(null);
    setModalOpen(true);
  }, [search]); /* eslint-disable-next-line */

  /* ── Ouverture auto depuis le Dashboard (clic sur ligne DrillCellPanel) ── */
  useEffect(() => {
    if (autoOpenRef.current) return;
    const sp = new URLSearchParams(search);
    const editRembId    = sp.get('edit-remb');
    const openSimulInvId = sp.get('open-simul');
    if (!editRembId && !openSimulInvId) return;

    /* Mémorise l'URL de retour Dashboard (une seule fois) */
    if (sp.get('from') === 'dashboard' && !backToDashboardRef.current) {
      const q = new URLSearchParams({ 'drill-annee': sp.get('drill-annee'), 'drill-mois': sp.get('drill-mois') });
      if (sp.get('drill-plat')) q.set('drill-plat', sp.get('drill-plat'));
      backToDashboardRef.current = `/?${q}`;
    }

    if (editRembId && allRows.length) {
      const remb = allRows.find(r => r.id === Number(editRembId));
      if (remb) {
        autoOpenRef.current = true;
        navigate('/remboursements', { replace: true });
        openEdit(remb);
      }
    }

    if (openSimulInvId && investissements.length && plateformes.length) {
      const invId = Number(openSimulInvId);
      const inv = investissements.find(i => i.id === invId);
      if (inv) {
        autoOpenRef.current = true;
        navigate('/remboursements', { replace: true });
        openFromSimul({
          investissement_id: invId,
          date_prevue:       sp.get('simul-date') || '',
          capital_prevu:     Number(sp.get('simul-capital')  || 0),
          interets_prevus:   Number(sp.get('simul-interets') || 0),
        });
      }
    }
  }, [allRows.length, investissements.length, plateformes.length]); /* eslint-disable-next-line */

  /* ── Modal helpers ── */
  const openNew = () => {
    setEditingId(null);
    setForm({ ...empty, investissement_id: '' });
    setErr(null); setModalOpen(true);
  };

  const openEdit = (r) => {
    setEditingId(r.id);
    const isBonus = r.type === 'bonus_parrainage' || r.type === 'bonus_plateforme';
    const sentinelle = r.type === 'bonus_parrainage' ? 'BONUS_PARRAINAGE' : r.type === 'bonus_plateforme' ? 'BONUS_PLATEFORME' : '';
    setForm({
      investissement_id: isBonus ? sentinelle : r.investissement_id,
      date_remb: r.date_remb,
      capital: r.capital, cashback: r.cashback || 0,
      interets_bruts_avant_local: r.interets_bruts_avant_local || 0,
      taxe_locale: r.taxe_locale || 0,
      interets_bruts: r.interets_bruts,
      prelev_sociaux: r.prelev_sociaux, prelev_forfaitaire: r.prelev_forfaitaire,
      statut: r.statut, notes: r.notes || '',
      methode_remboursement: r.methode_remboursement || 'portefeuille',
      compte_id: r.compte_id || '',
      bonus_plateforme_id: r.bonus_plateforme_id || '',
      bonus_investisseur_id: r.bonus_investisseur_id || '',
    });
    setErr(null); setModalOpen(true);
    // Charge les comptes du détenteur pour le dropdown Compte de réception
    if (!isBonus) {
      const invForEdit = investissements.find(i => i.id === r.investissement_id);
      if (invForEdit?.investisseur_id) {
        api.get(`/investissements/comptes-par-investisseur/${invForEdit.investisseur_id}`)
          .then(setComptesInvestisseur)
          .catch(() => setComptesInvestisseur([]));
      } else {
        setComptesInvestisseur([]);
      }
    }
  };

  /* Ouvre le formulaire remboursement pré-rempli depuis une ligne de projection */
  const openFromSimul = (s) => {
    const inv  = investissements.find(i => i.id === s.investissement_id);
    const plat = inv ? plateformes.find(p => p.id === inv.plateforme_id) : null;
    const bruts = s.interets_prevus || 0;
    const rates = getRatesForYear(s.date_prevue);
    const methode = plat && plat.methode_remboursement !== 'choix_investisseur'
      ? plat.methode_remboursement
      : (inv?.methode_remboursement || 'portefeuille');
    const hasLocalTax     = plat?.fiscalite === 'avec_fiscalite_locale' && plat?.taux_fiscalite_locale;
    const taxe_locale     = hasLocalTax ? round2(bruts * plat.taux_fiscalite_locale / 100) : 0;
    const brutsApresLocal = hasLocalTax ? round2(bruts - taxe_locale) : bruts;
    setEditingId(null);
    setForm({
      ...empty,
      investissement_id:          s.investissement_id,
      date_remb:                  s.date_prevue,
      capital:                    s.capital_prevu  || 0,
      cashback:                   0,
      interets_bruts_avant_local: hasLocalTax ? bruts : 0,
      taxe_locale,
      interets_bruts:             brutsApresLocal,
      prelev_sociaux:             rates ? round2(brutsApresLocal * rates.prelev_sociaux / 100) : 0,
      prelev_forfaitaire:         rates ? round2(brutsApresLocal * rates.impot_revenu   / 100) : 0,
      statut:                     'paye',
      notes:                      '',
      methode_remboursement:      methode,
      compte_id:                  methode === 'compte_courant' ? (inv?.compte_id || '') : '',
    });
    setErr(null);
    setModalOpen(true);
    // Charge les comptes du détenteur pour le dropdown Compte de réception
    if (inv?.investisseur_id) {
      api.get(`/investissements/comptes-par-investisseur/${inv.investisseur_id}`)
        .then(setComptesInvestisseur)
        .catch(() => setComptesInvestisseur([]));
    } else {
      setComptesInvestisseur([]);
    }
  };

  const openRowMenu = (e, row) => {
    e.stopPropagation();
    const rect = e.currentTarget.getBoundingClientRect();
    setOpenMenu({ row, x: rect.right, y: rect.bottom });
  };

  const deleteRemb = (id) => {
    setCorrDeleteConfirm({
      message: 'Supprimer définitivement ce remboursement ?',
      onConfirm: async () => {
        await api.del(`/remboursements/${id}`);
        setCorrDeleteConfirm(null);
        load();
      },
    });
  };

  const close = () => {
    setModalOpen(false); setEditingId(null); setForm(empty); setErr(null); setConfirmingDelete(false);
    if (backToDashboardRef.current) {
      const url = backToDashboardRef.current;
      backToDashboardRef.current = null;
      navigate(url);
    }
  };

  /* ── PFU rates ── */
  const getLastKnownRates = () =>
    pfuRates.reduce((best, r) => r.annee > best.annee ? r : best, pfuRates[0]);

  const getRatesForYear = (dateStr) => {
    if (!dateStr || !pfuRates.length) return null;
    const year = parseInt(dateStr.slice(0, 4), 10);
    return pfuRates.find(r => r.annee === year) ?? getLastKnownRates();
  };

  const round2 = (n) => Math.round(n * 100) / 100;

  const computeInteretsNets = (f) =>
    round2(Number(f.interets_bruts || 0) - Number(f.prelev_sociaux || 0) - Number(f.prelev_forfaitaire || 0));

  const computeNet = (f) =>
    round2(Number(f.capital || 0) + Number(f.cashback || 0) + computeInteretsNets(f));

  const setField = (k, v) => {
    const next = { ...form, [k]: v };

    // Fiscalité locale : calcule taxe_locale et interets_bruts à partir du brut avant retenue
    if (k === 'interets_bruts_avant_local') {
      const inv  = investissements.find(i => i.id === Number(next.investissement_id));
      const plat = plateformes.find(p => p.id === inv?.plateforme_id);
      const taux = plat?.fiscalite === 'avec_fiscalite_locale' ? (plat?.taux_fiscalite_locale || 0) : 0;
      next.taxe_locale    = round2(Number(v) * taux / 100);
      next.interets_bruts = round2(Number(v) - next.taxe_locale);
    }
    // Correction manuelle de la taxe locale : recalcule interets_bruts
    if (k === 'taxe_locale') {
      next.interets_bruts = round2(Number(next.interets_bruts_avant_local) - Number(v));
    }

    if (k === 'date_remb' || k === 'interets_bruts' || k === 'interets_bruts_avant_local' || k === 'taxe_locale') {
      const dateStr = k === 'date_remb' ? v : next.date_remb;
      const bruts   = Number(next.interets_bruts) || 0;
      const rates   = getRatesForYear(dateStr);
      if (rates) {
        next.prelev_sociaux     = round2(bruts * rates.prelev_sociaux / 100);
        next.prelev_forfaitaire = round2(bruts * rates.impot_revenu  / 100);
      }
    }
    // Quand l'investissement change, on hérite silencieusement de la méthode de la plateforme
    // (si fermée) ou on remet le défaut (si ouverte, l'utilisateur choisira dans le formulaire)
    if (k === 'investissement_id' && !BONUS_VALUES.includes(v)) {
      const inv  = investissements.find(i => i.id === Number(v));
      const plat = plateformes.find(p => p.id === inv?.plateforme_id);
      if (plat && plat.methode_remboursement !== 'choix_investisseur') {
        next.methode_remboursement = plat.methode_remboursement;
      } else {
        next.methode_remboursement = inv?.methode_remboursement || 'portefeuille';
      }
      next.compte_id = '';
      // Réinitialise le brut avant fiscalité locale lors d'un changement d'investissement
      next.interets_bruts_avant_local = 0;
      // Charge les comptes du détenteur et auto-sélectionne si compte_courant
      if (inv?.investisseur_id) {
        api.get(`/investissements/comptes-par-investisseur/${inv.investisseur_id}`)
          .then(comptes => {
            setComptesInvestisseur(comptes);
            if (next.methode_remboursement === 'compte_courant') {
              // Priorité : compte lié à l'investissement, sinon premier compte_courant
              const inherited = inv.compte_id ? comptes.find(c => c.id === inv.compte_id) : null;
              const def = inherited ?? comptes.find(c => c.type === 'compte_courant') ?? comptes[0];
              if (def) setForm(f => ({ ...f, compte_id: String(def.id) }));
            }
          })
          .catch(() => setComptesInvestisseur([]));
      } else {
        setComptesInvestisseur([]);
      }
    }
    setForm(next);
  };

  const isBonus = BONUS_VALUES.includes(form.investissement_id);

  const submit = async (e) => {
    e?.preventDefault?.();
    setErr(null);
    try {
      let payload;
      if (isBonus) {
        payload = {
          type: BONUS_TYPE_MAP[form.investissement_id],
          bonus_plateforme_id: Number(form.bonus_plateforme_id),
          bonus_investisseur_id: form.bonus_investisseur_id ? Number(form.bonus_investisseur_id) : undefined,
          date_remb: form.date_remb,
          cashback: Number(form.cashback || 0),
          statut: form.statut,
          notes: form.notes || undefined,
        };
      } else {
        payload = {
          type: 'normal',
          investissement_id: Number(form.investissement_id),
          date_remb: form.date_remb,
          capital: Number(form.capital || 0),
          cashback: Number(form.cashback || 0),
          interets_bruts_avant_local: Number(form.interets_bruts_avant_local || 0),
          taxe_locale: Number(form.taxe_locale || 0),
          interets_bruts: Number(form.interets_bruts || 0),
          prelev_sociaux: Number(form.prelev_sociaux || 0),
          prelev_forfaitaire: Number(form.prelev_forfaitaire || 0),
          statut: form.statut,
          notes: form.notes || undefined,
          methode_remboursement: form.methode_remboursement || 'portefeuille',
          compte_id: form.methode_remboursement === 'compte_courant' && form.compte_id ? Number(form.compte_id) : null,
        };
      }
      if (editingId) await api.put(`/remboursements/${editingId}`, payload);
      else await api.post('/remboursements', payload);
      close(); await load();
    } catch (e) { setErr(e.message); }
  };

  const onDelete = async () => {
    await api.del(`/remboursements/${editingId}`);
    close(); load();
  };

  /* ── Projections : helper taux PFU ── */
  const getPfuReduction = (dateStr) => {
    if (!dateStr || !pfuRates.length) return 0;
    const year = parseInt(dateStr.slice(0, 4), 10);
    const rates = pfuRates.find(r => r.annee === year) ?? getLastKnownRates();
    return (rates.prelev_sociaux + rates.impot_revenu) / 100;
  };

  /* ── Projections : totaux ── */
  const simulInv    = investissements.find(i => i.id === Number(selectedSimul));
  const simulTotals = echeances.reduce((acc, e) => {
    const brut = e.interets_prevus || 0;
    const reduction = getPfuReduction(e.date_prevue);
    acc.capital      += e.capital_prevu || 0;
    acc.interets     += brut;
    acc.interets_net += brut * (1 - reduction);
    acc.total        += e.total_prevu   || 0;
    return acc;
  }, { capital: 0, interets: 0, interets_net: 0, total: 0 });

  const multiDetenteur = new Set(plateformes.map(p => p.investisseur_id)).size > 1;

  /* ── Rendu ── */
  if (platLoaded && !loading && plateformes.length === 0) return (
    <>
      <div className="topbar"><h2>Remboursements</h2></div>
      <EmptyState />
    </>
  );
  return (
    <>
      <div className="topbar">
        <h2><PageIcon name="remboursement" />Remboursements</h2>
        {filterPlatId && (
          <button className="dr-clear-btn" onClick={() => setFilterPlatId('')}>
            ✕ Effacer le filtre plateforme
          </button>
        )}
      </div>

      {/* ── Graphiques ── */}
      {!listFocused && <div className="charts-row">
        <InteretsChart
          rows={chartRows}
          netMode={netMode}
        />
        <InteretsDistributionChart
          rows={chartRows}
          netMode={netMode}
        />
      </div>}

      {/* ── KPIs ── */}
      {!listFocused && <div className="dr-kpi-row">
        <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.capital)}</span>
            <TrendBadge current={totals.capital} prev={prevTotals.capital} />
          </div>
          <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>{fmtEUR(prevTotals.capital)} en {rembPrevYear}</div>
        </div>
        <div className="kpi">
          <div className="label">Cashback</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '4px 0 0' }}>
            <span style={{ fontSize: '1.35rem', fontWeight: 700 }}>{fmtEUR(totals.cashback)}</span>
            <TrendBadge current={totals.cashback} prev={prevTotals.cashback} />
          </div>
          <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>{fmtEUR(prevTotals.cashback)} en {rembPrevYear}</div>
        </div>
        <div className="kpi">
          <div className="label">Intérêts — {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.interets_nets : totals.interets)}</span>
            <TrendBadge current={netMode ? totals.interets_nets : totals.interets} prev={netMode ? prevTotals.interets_nets : prevTotals.interets} />
          </div>
          <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>{fmtEUR(netMode ? prevTotals.interets_nets : prevTotals.interets)} en {rembPrevYear}</div>
        </div>
      </div>}

      {/* ── Onglets ── */}
      {!listFocused && <div className="dr-tabs">
        <button className={`dr-tab${activeTab === 'plateformes'    ? ' active' : ''}`}
          onClick={() => setActiveTab('plateformes')}>Plateformes</button>
        <button className={`dr-tab${activeTab === 'vision-mensuelle' ? ' active' : ''}`}
          onClick={() => setActiveTab('vision-mensuelle')}>Vision mensuelle</button>
        <button className={`dr-tab${activeTab === 'remboursements' ? ' active' : ''}`}
          onClick={() => setActiveTab('remboursements')}>Remboursements</button>
        <button className={`dr-tab${activeTab === 'projections'    ? ' active' : ''}`}
          onClick={() => setActiveTab('projections')}>Projections Échéances</button>
      </div>}

      {/* ══ ONGLET PLATEFORMES ══ */}
      {activeTab === 'plateformes' && (
        <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 }}>
                Répartition par plateforme
                {rembPlatYear && <span style={{ marginLeft: 8 }}>pour l'année {rembPlatYear}</span>}
              </h3>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                <select value={rembPlatYear} onChange={e => setRembPlatYear(e.target.value)}
                  style={{
                    fontSize: 'var(--fs-xs)', padding: '4px 8px', height: 30,
                    borderRadius: 6, border: '1px solid var(--border)',
                    background: 'var(--surface-2)', color: 'var(--text-muted)',
                    cursor: 'pointer', outline: 'none',
                  }}>
                  <option value="">Toutes les années</option>
                  {years.map(y => <option key={y} value={y}>{y}</option>)}
                </select>
                {filterPlatId && (
                  <span style={{ fontSize: 12, color: 'var(--text-muted)', fontStyle: 'italic' }}>
                    Graphiques et KPIs filtrés sur cette plateforme
                  </span>
                )}
                <button
                  type="button"
                  className="icon-btn"
                  title={listFocused ? 'Réduire' : 'Agrandir'}
                  onClick={() => { const next = !listFocused; setListFocused(next); setRembPageSize(next ? 25 : 15); }}
                >
                  {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>
                <ExportDropdown
                  disabled={byPlatform.length === 0}
                  onCSV={()  => dlBlob(rembToCSV(allRows),  'remboursements.csv',  'text/csv;charset=utf-8')}
                  onXLS={()  => dlBlob(rembToXLS(allRows),  'remboursements.xlsx',  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')}
                  onJSON={()  => dlBlob(rembToJSON(allRows), 'remboursements.json', 'application/json')}
                />
              </div>
            </div>

            <table>
              <thead>
                <tr>
                  <th>Plateforme</th>
                  <th>Détenteur</th>
                  <th className="num">Capital remboursé</th>
                  <th className="num">Cashback</th>
                  <th className="num">Intérêts ({netMode ? 'Net' : 'Brut'})</th>
                  <th className="num">Cashback + Intérêts ({netMode ? 'Net' : 'Brut'})</th>
                  <th className="num">Échéances</th>
                  <th className="num" style={{ minWidth: 120 }}>Poids</th>
                  <th style={{ width: 28 }}></th>
                </tr>
              </thead>
              <tbody>
                {byPlatform.length === 0 && (
                  <tr><td colSpan={9} className="text-muted" style={{ textAlign: 'center', padding: 24 }}>
                    {loading ? 'Chargement…' : 'Aucun remboursement'}
                  </td></tr>
                )}
                {byPlatform.map(p => {
                  const isActive = String(filterPlatId) === String(p.plateforme_id);
                  const val      = netMode ? p.interets_nets : p.interets_bruts;
                  const poids    = totalInterets !== 0 ? (val / totalInterets) * 100 : 0;
                  return (
                    <tr key={p.plateforme_id}
                      className={`dr-row${isActive ? ' dr-row-selected' : ''}`}
                      style={{ cursor: 'pointer' }}
                      onClick={() => setFilterPlatId(isActive ? '' : String(p.plateforme_id))}
                      title={isActive ? 'Cliquer pour retirer le filtre' : 'Cliquer pour filtrer sur cette plateforme'}
                    >
                      <td><span style={{ fontWeight: isActive ? 600 : undefined }}>{p.nom}</span></td>
                      <td className="text-muted" style={{ fontSize: 'var(--fs-sm)' }}>{p.detenteur_nom || '—'}</td>
                      <td className="num">{fmtEUR(p.capital)}</td>
                      <td className="num">{p.cashback > 0 ? fmtEUR(p.cashback) : '—'}</td>
                      <td className="num">{fmtEUR(val)}</td>
                      <td className="num">{fmtEUR(p.cashback + val)}</td>
                      <td className="num" style={{ color: 'var(--text-muted)', fontSize: 'var(--fs-sm)' }}>{p.count}</td>
                      <td className="num">
                        <div style={{ display: 'flex', alignItems: 'center', gap: 6, justifyContent: 'flex-end' }}>
                          <div style={{ width: 48, height: 5, borderRadius: 3, background: 'var(--surface-2)', overflow: 'hidden' }}>
                            <div style={{ width: `${Math.max(0, poids)}%`, height: '100%', background: 'var(--primary)', borderRadius: 3 }} />
                          </div>
                          <span style={{ minWidth: 36, textAlign: 'right', fontSize: 'var(--fs-sm)' }}>
                            {poids.toFixed(1)} %
                          </span>
                        </div>
                      </td>
                      <td style={{ textAlign: 'center', color: 'var(--text-muted)', fontSize: 11 }}>
                        {isActive ? '✕' : ''}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
              {byPlatform.length > 1 && (
                <tfoot>
                  <tr style={{ borderTop: '2px solid var(--border)', fontWeight: 700, background: 'var(--surface-2)' }}>
                    <td>Total — {byPlatform.length} plateformes</td>
                    <td />
                    <td className="num">{fmtEUR(byPlatformTotals.capital)}</td>
                    <td className="num">{byPlatformTotals.cashback > 0 ? fmtEUR(byPlatformTotals.cashback) : '—'}</td>
                    <td className="num">{fmtEUR(netMode ? byPlatformTotals.interets_nets : byPlatformTotals.interets_bruts)}</td>
                    <td className="num">{fmtEUR(byPlatformTotals.cashback + (netMode ? byPlatformTotals.interets_nets : byPlatformTotals.interets_bruts))}</td>
                    <td className="num" style={{ color: 'var(--text-muted)', fontSize: 'var(--fs-sm)' }}>{byPlatformTotals.count}</td>
                    <td className="num"><span style={{ fontSize: 'var(--fs-sm)', color: 'var(--text-muted)' }}>100 %</span></td>
                    <td />
                  </tr>
                </tfoot>
              )}
            </table>
          </div>
        </div>
      )}

      {/* ══ ONGLET VISION MENSUELLE ══ */}
      {activeTab === 'vision-mensuelle' && (
        <div style={{ padding: '0 24px' }}>
          {/* Ancre fixe pour le scroll retour au tableau — toujours dans le DOM */}
          <div ref={tipTableRef} />
          <InteretsChartProvider netMode={netMode} pfuRates={pfuRates} activeView={activeView} activeId={activeId}>
            {!drillCell && <div><TableauInteretsPlateforme
              activeView={activeView}
              activeId={activeId}
              pfuRates={pfuRates}
              onCapitalMensuel={() => {}}
              onCellClick={handleCellClick}
              activeCell={drillCell}
              expandButton={
                <button
                  type="button"
                  className="icon-btn"
                  title={listFocused ? 'Réduire' : 'Agrandir'}
                  style={{ marginLeft: 4 }}
                  onClick={() => { const next = !listFocused; setListFocused(next); setRembPageSize(next ? 25 : 15); }}
                >
                  {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>}
            {/* ── Panneau de détail : Remboursements reçus et projection ── */}
            <div ref={drillPanelRef}>
            <DrillCellPanel
              cell={drillCell}
              onClose={() => setDrillCell(null)}
              pfuRates={pfuRates}
              activeView={activeView}
              activeId={activeId}
              onEditRecu={openEdit}
              onEditProjet={openFromSimul}
              refreshKey={drillRefreshKey}
              investissements={investissements}
              plateformes={plateformes}
              onBulkDone={load}
            />
            </div>
          </InteretsChartProvider>
        </div>
      )}

      {/* ══ ONGLET REMBOURSEMENTS ══ */}
      {activeTab === 'remboursements' && (
        <div style={{ padding: '0 24px' }}>
          <div className="card">
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
              <h3 style={{ margin: 0 }}>Remboursements</h3>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                {/* Filtre porte-monnaie */}
                <button
                  type="button"
                  className="icon-btn"
                  title={filterPortefeuille ? 'Masquer porte-monnaie' : 'Afficher porte-monnaie'}
                  onClick={() => setFilterPortefeuille(v => !v)}
                  style={{ opacity: filterPortefeuille ? 1 : 0.35, padding: 3 }}
                >
                  {libIcons['porte-monnaie']
                    ? <img src={ICONS_BASE + libIcons['porte-monnaie']} width={20} height={20} style={{ display: 'block', filter: 'var(--icon-filter, none)' }} />
                    : <span style={{ width: 20, height: 20, display: 'block', borderRadius: 3, background: 'var(--text-muted)' }} />}
                </button>
                {/* Filtre compte courant */}
                <button
                  type="button"
                  className="icon-btn"
                  title={filterCompteCourant ? 'Masquer compte courant' : 'Afficher compte courant'}
                  onClick={() => setFilterCompteCourant(v => !v)}
                  style={{ opacity: filterCompteCourant ? 1 : 0.35, padding: 3 }}
                >
                  {libIcons['compte-courant']
                    ? <img src={ICONS_BASE + libIcons['compte-courant']} width={20} height={20} style={{ display: 'block', filter: 'var(--icon-filter, none)' }} />
                    : <span style={{ width: 20, height: 20, display: 'block', borderRadius: 3, background: 'var(--text-muted)' }} />}
                </button>
                <button
                  type="button"
                  className="icon-btn"
                  title={listFocused ? 'Réduire' : 'Agrandir'}
                  onClick={() => { const next = !listFocused; setListFocused(next); setRembPageSize(next ? 25 : 15); }}
                >
                  {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>
                <ExportDropdown
                  disabled={tableRows.length === 0}
                  onCSV={()  => dlBlob(rembToCSV(tableRows),  'remboursements.csv',  'text/csv;charset=utf-8')}
                  onXLS={()  => dlBlob(rembToXLS(tableRows),  'remboursements.xlsx',  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')}
                  onJSON={()  => dlBlob(rembToJSON(tableRows), 'remboursements.json', 'application/json')}
                />
              </div>
            </div>

            {/* Filtres */}
            <div className="row" style={{ marginBottom: 12 }}>
              <div>
                <label>Plateforme</label>
                <select value={tableFilter.plateforme_id} onChange={e => setTableFilter({ ...tableFilter, plateforme_id: e.target.value })}>
                  <option value="">Toutes</option>
                  {plateformes.map(p => <option key={p.id} value={p.id}>{p.nom}{multiDetenteur && p.investisseur_nom ? ` — ${p.investisseur_nom}` : ''}</option>)}
                </select>
              </div>
              <div>
                <label>Type</label>
                <select value={tableFilter.type} onChange={e => setTableFilter({ ...tableFilter, type: e.target.value, investissement_id: '' })}>
                  <option value="">Tous</option>
                  <option value="normal">Remboursements</option>
                  <option value="bonus_parrainage">Bonus Parrainage</option>
                  <option value="bonus_plateforme">Bonus Plateforme</option>
                  <option value="correction_solde">Corrections de solde</option>
                </select>
              </div>
              <div>
                <label>Projet</label>
                <select value={tableFilter.investissement_id}
                  onChange={e => setTableFilter({ ...tableFilter, investissement_id: e.target.value, type: e.target.value ? 'normal' : tableFilter.type })}
                  disabled={tableFilter.type && tableFilter.type !== 'normal'}>
                  <option value="">Tous</option>
                  {investissements.map(i => <option key={i.id} value={i.id}>{i.nom_projet}</option>)}
                </select>
              </div>
              <div>
                <label>Année</label>
                <select value={tableFilter.year} onChange={e => setTableFilter({ ...tableFilter, year: e.target.value })}>
                  <option value="">Toutes</option>
                  {years.map(y => <option key={y} value={y}>{y}</option>)}
                </select>
              </div>
              <div>
                <label>Mois</label>
                <select value={tableFilter.month} onChange={e => setTableFilter({ ...tableFilter, month: e.target.value })}>
                  <option value="">Tous</option>
                  {MOIS_FR.map((m, i) => <option key={i+1} value={String(i+1).padStart(2,'0')}>{m}</option>)}
                </select>
              </div>
            </div>

            {/* Tableau */}
            <table>
              <thead>
                <tr>
                  <th>Date</th><th>Plateforme</th><th>Détenteur</th><th>Nom du projet</th><th>Versement</th>
                  <th className="num">Capital Remboursé</th><th className="num">Capital Restant dû</th>
                  <th className="num">Cashback</th>
                  <th className="num">Intérêts Bruts</th>
                  <th className="num">Prélèv. sociaux</th><th className="num">Impôt revenu</th>
                  <th className="num">Intérêts Nets</th>
                  <th className="num">Montant Net</th>
                  <th style={{ width: 36 }}></th>
                </tr>
              </thead>
              <tbody>
                {tableRows.length === 0 && (
                  <tr><td colSpan={14} className="text-muted" style={{ textAlign: 'center', padding: 24 }}>
                    {loading ? 'Chargement…' : 'Aucun remboursement'}
                  </td></tr>
                )}
                {pagedTableRows.map(r => {
                  const isBonus       = r.type === 'bonus_parrainage' || r.type === 'bonus_plateforme';
                  const isCorrection  = r._is_correction === true;
                  const rowKey = isCorrection ? `corr-${r.id}` : `remb-${r.id}`;
                  return (
                    <tr key={rowKey} style={{ cursor: 'pointer' }}
                      title={isCorrection ? 'Cliquer pour supprimer cette correction' : 'Modifier ce remboursement'}
                      onClick={() => {
                        if (isCorrection) {
                          setCorrDeleteConfirm({
                            message: `Supprimer la correction de ${r.montant > 0 ? '+' : ''}${r.montant} € du ${fmtDate(r.date_remb)} ?`,
                            onConfirm: () => {
                              api.del(`/corrections/${r.id}`).then(() => load()).catch(console.error);
                              setCorrDeleteConfirm(null);
                            },
                          });
                        } else {
                          openEdit(r);
                        }
                      }}>
                      <td>{fmtDate(r.date_remb)}</td>
                      <td>{r.plateforme_nom}</td>
                      <td className="text-muted" style={{ fontSize: 'var(--fs-sm)' }}>
                        {isCorrection ? (r.investisseur_nom || '—') : (r.plateforme_detenteur_nom || '—')}
                      </td>
                      <td>
                        {isCorrection
                          ? <span style={{ color: 'var(--text-muted)', fontStyle: 'italic' }}>{r.nom_projet}</span>
                          : isBonus
                            ? <span style={{ color: 'var(--text-muted)', fontStyle: 'italic' }}>{r.nom_projet}</span>
                            : r.nom_projet}
                      </td>
                      <td style={{ fontSize: 'var(--fs-sm)' }}>
                        {isCorrection ? (
                          <span className="text-muted" style={{ fontStyle: 'italic' }}>Correction</span>
                        ) : isBonus ? (
                          <span className="text-muted" style={{ fontStyle: 'italic' }}>
                            {r.type === 'bonus_parrainage' ? 'Parrainage' : 'Bonus'}
                          </span>
                        ) : r.methode_remboursement === 'compte_courant' ? (
                          <span title={r.compte_nom || r.nom_compte_courant || ''}>
                            {r.compte_nom || r.nom_compte_courant || <span className="text-muted">Compte courant</span>}
                          </span>
                        ) : (
                          <span className="text-muted">Porte-monnaie</span>
                        )}
                      </td>
                      <td className="num">{(isBonus || isCorrection) ? '—' : fmtEUR(r.capital)}</td>
                      <td className="num" style={{ color: !isBonus && !isCorrection && r.capital_restant_du <= 0 ? 'var(--success)' : undefined }}>
                        {(isBonus || isCorrection) ? '—' : fmtEUR(Math.max(0, r.capital_restant_du ?? 0))}
                      </td>
                      <td className="num">{r.cashback ? fmtEUR(r.cashback) : '—'}</td>
                      <td className="num">{(isBonus || isCorrection) ? '—' : fmtEUR(r.interets_bruts)}</td>
                      <td className="num">{(isBonus || isCorrection) ? '—' : fmtEUR(r.prelev_sociaux)}</td>
                      <td className="num">{(isBonus || isCorrection) ? '—' : fmtEUR(r.prelev_forfaitaire)}</td>
                      <td className="num">
                        {isCorrection
                          ? <span style={{ color: r.montant >= 0 ? 'var(--success)' : 'var(--danger)', fontWeight: 600 }}>
                              {r.montant >= 0 ? '+' : ''}{fmtEUR(r.montant)}
                            </span>
                          : isBonus ? '—' : fmtEUR(r.interets_nets)}
                      </td>
                      <td className="num">
                        {isCorrection
                          ? <span style={{ color: r.montant >= 0 ? 'var(--success)' : 'var(--danger)', fontWeight: 600 }}>
                              {r.montant >= 0 ? '+' : ''}{fmtEUR(r.montant)}
                            </span>
                          : fmtEUR(r.net_recu)}
                      </td>
                      <td style={{ width: 36, textAlign: 'center' }} onClick={e => e.stopPropagation()}>
                        <button
                          style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px 6px', borderRadius: 4, color: 'var(--text-muted)', lineHeight: 1, fontSize: 16 }}
                          onClick={e => openRowMenu(e, r)}>⋮</button>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
            <Pagination
              page={rembPage} setPage={setRembPage}
              pageSize={rembPageSize} setPageSize={setRembPageSize}
              totalPages={rembTotalPages} totalItems={rembTotalItems}
              PAGE_SIZES={PAGE_SIZES}
            />
          </div>
        </div>
      )}

      {/* ══ ONGLET PROJECTIONS ÉCHÉANCES ══ */}
      {activeTab === 'projections' && (
        <div style={{ padding: '0 24px' }}>
          <div className="card" style={{ marginBottom: 16 }}>
            <div className="row">
              <div style={{ flex: 2 }}>
                <label>Investissement</label>
                <select value={selectedSimul} onChange={e => setSelectedSimul(e.target.value)}>
                  <option value="">— Choisir —</option>
                  {investissements.map(i => (
                    <option key={i.id} value={i.id}>
                      {i.nom_projet} ({fmtEUR(i.montant_investi)} – {i.taux_interet ?? '?'} % – {i.duree_mois ?? '?'} m – {i.type_remb || '?'})
                    </option>
                  ))}
                </select>
              </div>
              <div style={{ flex: 1 }}>
                <button className="primary" onClick={generateSimul}
                  disabled={!selectedSimul || simulBusy} style={{ width: '100%' }}>
                  {simulBusy ? '…' : 'Générer / Régénérer'}
                </button>
              </div>
              <div style={{ display: 'flex', alignItems: 'flex-end', paddingBottom: 2 }}>
                <button
                  type="button"
                  className="icon-btn"
                  title={listFocused ? 'Réduire' : 'Agrandir'}
                  onClick={() => { const next = !listFocused; setListFocused(next); setRembPageSize(next ? 25 : 15); }}
                >
                  {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>
            {simulMsg && (
              <div className={simulMsg.startsWith('✔') ? 'success-msg' : 'error'} style={{ marginTop: 12 }}>
                {simulMsg}
              </div>
            )}
            {simulInv && (!simulInv.taux_interet || !simulInv.duree_mois) && (
              <div className="error" style={{ marginTop: 12 }}>
                Cet investissement n'a pas de <strong>taux</strong> et/ou de <strong>durée</strong>. Renseignez-les dans la fiche.
              </div>
            )}
          </div>

          {/* ── Tableau / état vide ── */}
          {(() => {
            /* Détermine le message d'état vide selon le contexte */
            let emptyIcon = null;
            let emptyTitle = null;
            let emptyHint = null;

            if (loading) {
              emptyTitle = 'Chargement…';
            } else if (investissements.length === 0) {
              emptyIcon = (
                <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.3, marginBottom: 10 }}>
                  <path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/>
                </svg>
              );
              emptyTitle = 'Aucun investissement enregistré';
              emptyHint  = 'Créez votre premier investissement pour visualiser les projections d\'échéances.';
            } else if (investissements.every(i => i.statut === 'rembourse')) {
              emptyIcon = (
                <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.3, marginBottom: 10 }}>
                  <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/>
                </svg>
              );
              emptyTitle = 'Tous les investissements ont été remboursés';
              emptyHint  = 'Il n\'y a plus de projection à afficher. Les projections concernent les projets encore en cours.';
            } else if (!selectedSimul) {
              emptyIcon = (
                <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.3, marginBottom: 10 }}>
                  <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
                </svg>
              );
              emptyTitle = 'Aucun projet sélectionné';
              emptyHint  = 'Sélectionnez un projet dans la liste ci-dessus pour visualiser son échéancier prévisionnel.';
            } else if (selectedSimul && echeances.length === 0 && !simulBusy) {
              emptyIcon = (
                <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.3, marginBottom: 10 }}>
                  <rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>
                  <path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/>
                </svg>
              );
              emptyTitle = 'Échéancier non généré';
              emptyHint  = 'Cliquez sur « Générer / Régénérer » ci-dessus pour créer la projection de ce projet.';
            }

            const isEmpty = !!(emptyTitle && echeances.length === 0);

            return (
              <div className="card">
                {!isEmpty && (
                  <div className="kpi-grid" style={{ marginBottom: 12 }}>
                    <div className="kpi">
                      <div className="label">Capital prévu</div>
                      <div className="value">{fmtEUR(simulTotals.capital)}</div>
                    </div>
                    <div className="kpi">
                      <div className="label">
                        Intérêts prévus — {netMode ? 'Net (estimé)' : 'Brut'}
                      </div>
                      <div className="value success">
                        {fmtEUR(netMode ? simulTotals.interets_net : simulTotals.interets)}
                      </div>
                    </div>
                    <div className="kpi">
                      <div className="label">Total prévu</div>
                      <div className="value">{fmtEUR(simulTotals.total)}</div>
                    </div>
                  </div>
                )}
                <table>
                  <thead>
                    <tr>
                      <th>#</th>
                      <th>Date prévue</th>
                      <th className="num">Capital</th>
                      <th className="num">Intérêts ({netMode ? 'Net estimé' : 'Brut'})</th>
                      <th className="num">Total échéance</th>
                    </tr>
                  </thead>
                  <tbody>
                    {isEmpty ? (
                      <tr>
                        <td colSpan={5} style={{ textAlign: 'center', padding: '48px 24px', height: 220 }}>
                          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6, color: 'var(--text-muted)' }}>
                            {emptyIcon}
                            <span style={{ fontWeight: 600, fontSize: '0.95rem', color: 'var(--text)' }}>{emptyTitle}</span>
                            {emptyHint && <span style={{ fontSize: '0.85rem', maxWidth: 360, textAlign: 'center', lineHeight: 1.5 }}>{emptyHint}</span>}
                          </div>
                        </td>
                      </tr>
                    ) : (
                      echeances.map(e => {
                        const reduction = getPfuReduction(e.date_prevue);
                        const interets  = netMode
                          ? (e.interets_prevus || 0) * (1 - reduction)
                          : (e.interets_prevus || 0);
                        return (
                          <tr key={e.id}>
                            <td>{e.numero_echeance}</td>
                            <td>{fmtDate(e.date_prevue)}</td>
                            <td className="num">{fmtEUR(e.capital_prevu)}</td>
                            <td className="num">{fmtEUR(interets)}</td>
                            <td className="num">{fmtEUR(e.total_prevu)}</td>
                          </tr>
                        );
                      })
                    )}
                  </tbody>
                </table>
              </div>
            );
          })()}
        </div>
      )}

      {/* ══ MODAL ══ */}
      {(() => {
        const pfuYear  = getRatesForYear(form.date_remb);
        const fmtRate  = (n) => n != null ? n.toFixed(1).replace('.', ',') + ' %' : '…';
        const labelPS  = `Prélèvements sociaux${pfuYear ? ` (${fmtRate(pfuYear.prelev_sociaux)})` : ''} (€)`;
        const labelIR  = `Impôt sur le revenu${pfuYear  ? ` (${fmtRate(pfuYear.impot_revenu)})`   : ''} (€)`;
        const interetsNets = computeInteretsNets(form);

        // Liste d'investissements disponibles dans le select
        const invListForSelect = (editingId
          ? investissements.filter(i => i.statut !== 'rembourse' || i.id === Number(form.investissement_id))
          : investissementsActifs
        ).slice().sort((a, b) => {
          const pa = (a.plateforme_nom || '').toLowerCase();
          const pb = (b.plateforme_nom || '').toLowerCase();
          if (pa !== pb) return pa.localeCompare(pb, 'fr');
          return (a.nom_projet || '').localeCompare(b.nom_projet || '', 'fr');
        });

        // Méthode de remboursement — plateforme de l'investissement sélectionné
        const currentInv  = !isBonus ? investissements.find(i => i.id === Number(form.investissement_id)) : null;
        const currentPlat = currentInv ? plateformes.find(p => p.id === currentInv.plateforme_id) : null;
        const isChoixOuvert = currentPlat?.methode_remboursement === 'choix_investisseur';
        const hasLocalTax   = !isBonus && currentPlat?.fiscalite === 'avec_fiscalite_locale' && currentPlat?.taux_fiscalite_locale;
        const isExonere     = !isBonus && currentInv?.fiscalite_override === 'exonere';
        const isIndicatif   = isExonere || (!isBonus && !!currentPlat && currentPlat?.fiscalite !== 'flat_tax');
        const netRecu       = isIndicatif
          ? round2(Number(form.capital||0) + Number(form.cashback||0) + Number(form.interets_bruts||0))
          : computeNet(form);

        return (
          <Modal
            open={modalOpen}
            title={editingId ? 'Modifier le remboursement' : 'Nouveau remboursement'}
            onClose={close}
            width={900}
            footer={
              <div style={{ display: 'flex', alignItems: 'center', width: '100%', gap: 8 }}>
                <div style={{ flex: 1 }}>
                  {editingId && (
                    !confirmingDelete ? (
                      <button className="danger" onClick={() => setConfirmingDelete(true)}>
                        Supprimer
                      </button>
                    ) : (
                      <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                        <span style={{ fontSize: 13, color: 'var(--danger, #ef4444)', whiteSpace: 'nowrap' }}>
                          Supprimer définitivement ?
                        </span>
                        <button onClick={() => setConfirmingDelete(false)}>Non</button>
                        <button className="danger" onClick={onDelete}>Oui, supprimer</button>
                      </span>
                    )
                  )}
                </div>
                <button onClick={close}>Annuler</button>
                <button className="primary" onClick={submit}>{editingId ? 'Enregistrer' : 'Créer'}</button>
              </div>
            }
          >
            <form onSubmit={submit}>
              {err && <div className="error">{err}</div>}
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '12px 16px' }}>
                {/* ── Sélecteur d'investissement ── */}
                <div style={{ gridColumn: isBonus ? 'span 1' : 'span 3' }}>
                  <label>Investissement *</label>
                  <select required value={form.investissement_id}
                    onChange={e => setField('investissement_id', e.target.value)}>
                    <option value="">—</option>
                    <option value="BONUS_PARRAINAGE">🎁 Bonus Parrainage</option>
                    <option value="BONUS_PLATEFORME">🏆 Bonus Plateforme</option>
                    <optgroup label="──────────────────" />
                    {invListForSelect.map(i =>
                      <option key={i.id} value={i.id}>{i.plateforme_nom} — {i.nom_projet} ({fmtEUR(i.montant_investi)})</option>
                    )}
                  </select>
                </div>
                {isBonus && (
                  <div style={{ gridColumn: 'span 2' }}>
                    <label>Plateforme associée (bonus)</label>
                    <select value={form.bonus_plateforme_id} onChange={e => {
                        const plat = plateformes.find(p => String(p.id) === e.target.value);
                        setForm({ ...form, bonus_plateforme_id: e.target.value, bonus_investisseur_id: plat?.investisseur_id ? String(plat.investisseur_id) : '' });
                      }}>
                      <option value="">— Aucune —</option>
                      {plateformes.map(p => <option key={p.id} value={p.id}>{p.nom}{multiDetenteur && p.investisseur_nom ? ` — ${p.investisseur_nom}` : ''}</option>)}
                    </select>
                  </div>
                )}

                {/* ── Champs remboursement normal ── */}
                {!isBonus && (<>
<div style={{ gridColumn: 'span 3', borderTop: '1px solid var(--border)', paddingTop: 4, marginTop: 4 }}>
                    <span style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', color: 'var(--text-muted)' }}>Remboursement</span>
                  </div>
                  {hasLocalTax && (
                    <div style={{ gridColumn: 'span 2' }}>
                      <label>Intérêts bruts avant retenue locale ({currentPlat.taux_fiscalite_locale} %) (€)</label>
                      <input type="number" step="0.01" value={form.interets_bruts_avant_local}
                        onChange={e => setField('interets_bruts_avant_local', e.target.value)} />
                    </div>
                  )}
                  {hasLocalTax && (
                    <div>
                      <label>Retenue à la source locale (€)</label>
                      <input type="number" step="0.01" value={form.taxe_locale}
                        onChange={e => setField('taxe_locale', e.target.value)} />
                    </div>
                  )}
                  <div>
                    <label>Capital (€)</label>
                    <input type="number" step="0.01" value={form.capital}
                      onChange={e => setField('capital', e.target.value)} />
                  </div>
                  <div>
                    <label>{hasLocalTax ? 'Intérêts bruts après retenue locale (€)' : 'Intérêts bruts (€)'}</label>
                    <input type="number" step="0.01" value={form.interets_bruts}
                      readOnly={!!hasLocalTax}
                      style={hasLocalTax ? { background: 'var(--surface-2)', color: 'var(--text-muted)', cursor: 'not-allowed' } : undefined}
                      onChange={e => !hasLocalTax && setField('interets_bruts', e.target.value)} />
                  </div>
                  <div>
                    <label>Cashback (€)</label>
                    <input type="number" step="0.01" value={form.cashback}
                      onChange={e => setField('cashback', e.target.value)} />
                  </div>
                  <div style={{ gridColumn: 'span 3', borderTop: '1px solid var(--border)', paddingTop: 4, marginTop: 4 }}>
                    <span style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', color: 'var(--text-muted)' }}>Imposition{isIndicatif ? ' — indicatif' : ''}</span>
                  </div>
                  <div>
                    <label>{labelPS}</label>
                    <input type="number" step="0.01" value={form.prelev_sociaux}
                      readOnly={isIndicatif}
                      style={isIndicatif ? { background: 'var(--surface-2)', color: 'var(--text-muted)', cursor: 'not-allowed' } : undefined}
                      onChange={e => !isIndicatif && setForm({ ...form, prelev_sociaux: Number(e.target.value) })} />
                  </div>
                  <div>
                    <label>{labelIR}</label>
                    <input type="number" step="0.01" value={form.prelev_forfaitaire}
                      readOnly={isIndicatif}
                      style={isIndicatif ? { background: 'var(--surface-2)', color: 'var(--text-muted)', cursor: 'not-allowed' } : undefined}
                      onChange={e => !isIndicatif && setForm({ ...form, prelev_forfaitaire: Number(e.target.value) })} />
                  </div>
                  <div>
                    <label>Total prélèvements (€)</label>
                    <input type="number" step="0.01"
                      value={round2((Number(form.prelev_sociaux) || 0) + (Number(form.prelev_forfaitaire) || 0))}
                      readOnly
                      style={{ background: 'var(--surface-2)', color: 'var(--text-muted)', cursor: 'not-allowed' }} />
                  </div>
                  <div style={{ gridColumn: 'span 3', display: 'flex', alignItems: 'center', gap: 8, fontSize: 13 }}>
                    <span style={{ color: 'var(--text-muted)' }}>Montant des intérêts après imposition</span>
                    <span style={{ fontWeight: 600, color: 'var(--text)' }}>{fmtEUR(interetsNets)}</span>
                  </div>
                  <div style={{ gridColumn: 'span 3', borderTop: '1px solid var(--border)', paddingTop: 4, marginTop: 4 }}>
                    <span style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', color: 'var(--text-muted)' }}>Versement</span>
                  </div>
                  <div>
                    <label>Date *</label>
                    <input type="date" required value={form.date_remb}
                      onChange={e => setField('date_remb', e.target.value)} />
                  </div>
                  <div>
                    <label>Méthode de remboursement</label>
                    <select value={form.methode_remboursement || 'portefeuille'}
                      onChange={e => {
                        const m = e.target.value;
                        const def = m === 'compte_courant' ? (comptesInvestisseur.find(c => c.type === 'compte_courant') ?? comptesInvestisseur[0]) : null;
                        setForm(f => ({ ...f, methode_remboursement: m, compte_id: def ? String(def.id) : '' }));
                      }}>
                      <option value="portefeuille">Porte-monnaie de la plateforme</option>
                      <option value="compte_courant">Compte courant de l'investisseur</option>
                    </select>
                  </div>
                  <div>
                    {form.methode_remboursement === 'compte_courant' && (
                    <>
                      <label>Compte de réception</label>
                      {comptesInvestisseur.length > 0 ? (
                        <select value={form.compte_id || ''}
                          onChange={e => setForm(f => ({ ...f, compte_id: e.target.value }))}>
                          <option value="">— Choisir un compte —</option>
                          {comptesInvestisseur.map(c => (
                            <option key={c.id} value={c.id}>{c.nom}{c.banque ? ` — ${c.banque}` : ''}</option>
                          ))}
                        </select>
                      ) : (
                        <p className="text-muted" style={{ fontSize: 'var(--fs-sm)', margin: '4px 0' }}>
                          Aucun compte défini. <a href="/settings?section=comptes" target="_blank" rel="noreferrer">Créer un compte →</a>
                        </p>
                      )}
                    </>
                  )}
                  <label>Montant versé (€)</label>
                    <input type="number" step="0.01" value={netRecu} readOnly
                      style={{ background: 'var(--bg-input-readonly, rgba(255,255,255,.05))', cursor: 'default' }} />
                  </div>
                  <div style={{ gridColumn: 'span 3', display: 'flex', alignItems: 'center', gap: 8, fontSize: 13 }}>
                    <span style={{ color: 'var(--text-muted)' }}>
                      {isIndicatif
                        ? "L'imposition n'est pas déduite du montant versé (fiscalité appliquée à titre indicatif)."
                        : "L'imposition est déduite du montant versé (capital + cashback + intérêts nets)."}
                    </span>
                  </div>
                </>)}

                {/* ── Bonus ── */}
                {isBonus && (
                  <div>
                    <label>Date *</label>
                    <input type="date" required value={form.date_remb}
                      onChange={e => setField('date_remb', e.target.value)} />
                  </div>
                )}
                {isBonus && (
                  <div style={{ gridColumn: 'span 2' }}>
                    <label>Montant (€)</label>
                    <input type="number" step="0.01" value={form.cashback}
                      onChange={e => setField('cashback', e.target.value)} />
                  </div>
                )}

              </div>
            </form>
          </Modal>
        );
      })()}
      {openMenu && (
        <>
          <div style={{ position: 'fixed', inset: 0, zIndex: 299 }} onClick={() => setOpenMenu(null)} />
          <div style={{
            position: 'fixed', left: openMenu.x, top: openMenu.y,
            transform: 'translateX(-100%) translateY(4px)',
            zIndex: 300,
            background: 'var(--surface)', border: '1px solid var(--border)',
            borderRadius: 8, boxShadow: '0 4px 20px rgba(0,0,0,0.15)',
            padding: '4px 0', minWidth: 140,
          }}>
            {!openMenu.row._is_correction && (
              <button
                style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '8px 14px', background: 'none', border: 'none', cursor: 'pointer', fontSize: 'var(--fs-sm)', color: 'var(--text)', textAlign: 'left' }}
                onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
                onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                onClick={() => { setOpenMenu(null); openEdit(openMenu.row); }}>
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
                Modifier
              </button>
            )}
            <button
              style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '8px 14px', background: 'none', border: 'none', cursor: 'pointer', fontSize: 'var(--fs-sm)', color: 'var(--danger)', textAlign: 'left' }}
              onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
              onMouseLeave={e => e.currentTarget.style.background = 'none'}
              onClick={() => {
                const row = openMenu.row;
                setOpenMenu(null);
                if (row._is_correction) {
                  setCorrDeleteConfirm({
                    message: 'Supprimer définitivement cette correction ?',
                    onConfirm: async () => {
                      await api.del(`/corrections/${row.id}`);
                      setCorrDeleteConfirm(null);
                      load();
                    },
                  });
                } else {
                  deleteRemb(row.id);
                }
              }}>
              <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4h6v2"/></svg>
              Supprimer
            </button>
          </div>
        </>
      )}
      {corrDeleteConfirm && (
        <ConfirmModal
          message={corrDeleteConfirm.message}
          onConfirm={corrDeleteConfirm.onConfirm}
          onCancel={() => setCorrDeleteConfirm(null)}
        />
      )}
    </>
  );
}
