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 { useLocation, useNavigate } from 'react-router-dom';
import { api } from '../api.js';
import InvSelect from '../components/InvSelect.jsx';
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 CountrySelect from '../components/CountrySelect.jsx';
import InvChart from '../components/InvChart.jsx';
import DistributionChart from '../components/DistributionChart.jsx';
import CapitalMensuelTable from '../components/CapitalMensuelTable.jsx';
import { fmtEUR, fmtPct, fmtDate, fmtStatut, today } from '../utils/format.js';
import * as XLSX from 'xlsx';
import EmptyState from '../components/EmptyState.jsx';

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

const TYPE_REMB_LABELS = { in_fine: 'In fine', amortissable: 'Amortissable', differe: 'Différé' };

/* ── Helper téléchargement ───────────────────────────────────── */
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);
}

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



/* ── Export investissements ──────────────────────────────────── */
function invToCSV(rows) {
  const BOM = '﻿'; const sep = ';';
  const q = v => `"${String(v ?? '').replace(/"/g, '""')}"`;
  const headers = [
    'Date souscription', 'Projet', 'Émetteur', 'Plateforme',
    'Montant investi (€)', 'Taux (%)', 'Durée (mois)', 'Type remb.',
    'Capital remboursé (€)', 'Capital restant dû (€)',
    'Intérêts bruts (€)', 'Intérêts nets (€)', 'Statut',
  ];
  const data = rows.map(r => [
    r.date_souscription,
    r.nom_projet,
    r.emetteur || '',
    r.plateforme_nom || '',
    String(r.montant_investi).replace('.', ','),
    r.taux_interet != null ? String(r.taux_interet).replace('.', ',') : '',
    r.duree_mois ?? '',
    TYPE_REMB_LABELS[r.type_remb] || r.type_remb || '',
    String(r.capital_rembourse || 0).replace('.', ','),
    String(Math.max(0, r.montant_investi - (r.capital_rembourse || 0))).replace('.', ','),
    String(r.interets_percus || 0).replace('.', ','),
    String(r.interets_nets_total || 0).replace('.', ','),
    r.statut || '',
  ]);
  return BOM + [headers, ...data].map(row => row.map(q).join(sep)).join('\r\n');
}

function invToXLS(rows) {
  const data = rows.map(r => {
    const capInv     = r.capital_total ?? r.montant_investi;
    const capRestant = Math.max(0, capInv - (r.capital_rembourse || 0));
    return {
      'Date souscription':    r.date_souscription,
      'Projet':               r.nom_projet,
      'Émetteur':             r.emetteur || '',
      'Plateforme':           r.plateforme_nom || '',
      'Montant investi (€)':  capInv,
      'Taux (%)':             r.taux_interet ?? '',
      'Durée (mois)':         r.duree_mois ?? '',
      'Type remb.':           TYPE_REMB_LABELS[r.type_remb] || r.type_remb || '',
      'Capital remboursé (€)': r.capital_rembourse || 0,
      'Capital restant dû (€)': capRestant,
      'Intérêts bruts (€)':   r.interets_percus || 0,
      'Intérêts nets (€)':    r.interets_nets_total || 0,
      'Statut':               r.statut || '',
    };
  });
  const ws = XLSX.utils.json_to_sheet(data);
  const wb = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(wb, ws, 'Investissements');
  return XLSX.write(wb, { type: 'array', bookType: 'xlsx' });
}

function invToJSON(rows) {
  return JSON.stringify(rows.map(r => ({
    date_souscription: r.date_souscription,
    nom_projet:        r.nom_projet,
    emetteur:          r.emetteur || null,
    plateforme:        r.plateforme_nom || '',
    montant_investi:   r.montant_investi,
    taux_interet:      r.taux_interet ?? null,
    duree_mois:        r.duree_mois ?? null,
    type_remb:         r.type_remb || '',
    capital_rembourse: r.capital_rembourse || 0,
    interets_bruts:    r.interets_percus  || 0,
    interets_nets:     r.interets_nets_total   || 0,
    statut:            r.statut,
  })), null, 2);
}

/* ── Export plateformes ──────────────────────────────────────── */
function platToCSV(rows) {
  const BOM = '﻿'; const sep = ';';
  const q = v => `"${String(v ?? '').replace(/"/g, '""')}"`;
  const headers = [
    'Plateforme', 'Projets', 'Montant investi (€)', 'En cours (€)',
    'Capital remboursé (€)', 'Intérêts bruts (€)', 'Intérêts nets (€)', 'Poids (%)',
  ];
  const data = rows.map(p => [
    p.nom, p.count,
    String(p.investi).replace('.', ','),
    String(p.encours).replace('.', ','),
    String(p.cap_remb).replace('.', ','),
    String(p.int_perc).replace('.', ','),
    String(p.int_perc_net).replace('.', ','),
    p.poids.toFixed(2).replace('.', ','),
  ]);
  return BOM + [headers, ...data].map(row => row.map(q).join(sep)).join('\r\n');
}

function platToXLS(rows) {
  const data = rows.map(p => ({
    'Plateforme':           p.nom,
    'Projets':              p.count,
    'Montant investi (€)':  p.investi,
    'En cours (€)':         p.encours,
    'Capital remboursé (€)': p.cap_remb,
    'Intérêts bruts (€)':   p.int_perc,
    'Intérêts nets (€)':    p.int_perc_net,
    'Poids (%)':            +p.poids.toFixed(2),
  }));
  const ws = XLSX.utils.json_to_sheet(data);
  const wb = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(wb, ws, 'Plateformes');
  return XLSX.write(wb, { type: 'array', bookType: 'xlsx' });
}

function platToJSON(rows) {
  return JSON.stringify(rows.map(p => ({
    plateforme:      p.nom,
    nb_projets:      p.count,
    montant_investi: p.investi,
    en_cours:        p.encours,
    capital_rembourse: p.cap_remb,
    interets_bruts:  p.int_perc,
    interets_nets:   p.int_perc_net,
    poids_pct:       +p.poids.toFixed(2),
  })), 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>
  );
}

/* ── Helpers form ────────────────────────────────────────────── */
const empty = {
  investisseur_id: '', plateforme_id: '', nom_projet: '', emetteur: '',
  date_souscription: today(), date_premiere_echeance: '', date_cible: '',
  montant_investi: '', taux_interet: '', duree_mois: '',
  type_remb: 'in_fine', freq_interets: 'mensuel',
  statut: 'en_cours', reference: '', notes: '',
  echeance_fin_de_mois: false, methode_remboursement: '', nom_compte_courant: '', compte_id: '', pays_exposition: 'FR',
  categories_inv_ids: [], secteurs_inv_ids: [],
};

function addMonthsFE(isoDate, n) {
  if (!isoDate || !n) return '';
  const [y, m, d] = isoDate.split('-').map(Number);
  const dt = new Date(Date.UTC(y, m - 1 + n, d));
  return dt.toISOString().slice(0, 10);
}

/** Retourne le dernier jour du mois de isoDate. Ex : '2024-01-28' → '2024-01-31' */
function lastDayOfMonthFE(isoDate) {
  if (!isoDate) return isoDate;
  const [y, m] = isoDate.split('-').map(Number);
  const dt = new Date(Date.UTC(y, m, 0)); // jour 0 du mois suivant
  return dt.toISOString().slice(0, 10);
}

/**
 * Ajoute n mois et positionne sur le dernier jour du mois cible.
 * Évite les débordements JS (31 jan + 1 = 3 mar → ici = 29 fév).
 */
function addMonthsFinDeMoisFE(isoDate, n) {
  if (!isoDate || (n === undefined || n === null)) return '';
  const [y, m] = isoDate.split('-').map(Number);
  const dt = new Date(Date.UTC(y, m - 1 + Number(n) + 1, 0));
  return dt.toISOString().slice(0, 10);
}

/** Retourne le numéro du jour dans le mois (1-31) ou 0 si absent. */
function dayOfMonth(isoDate) {
  if (!isoDate || isoDate.length < 10) return 0;
  return parseInt(isoDate.slice(8, 10), 10);
}

/* ── Composant principal ─────────────────────────────────────── */
export default function Investissements() {
  const { activeId, activeView, investisseurs } = useInvestisseur();
  const { displayMode } = useUi();
  const { search }   = useLocation();
  const navigate     = useNavigate();
  const platsRef     = useRef([]);
  const lastValidSouscriptionRef = useRef('');

  const [allRows,      setAllRows]      = useState([]);
  const [allRembs,     setAllRembs]     = useState([]);
  const [allReinvests, setAllReinvests] = useState([]);
  const [plats,      setPlats]      = useState([]);
  const [comptesCourants, setComptesCourants] = useState([]);
  const [comptesInvestisseur, setComptesInvestisseur] = useState([]);
  const [activeTab,  setActiveTab]  = useState('plateformes');
  const [listFocused, setListFocused] = useState(false);
  const [filter,     setFilter]     = useState({ statut: '', plateforme_id: '', categorie_inv_id: '', secteur_inv_id: '', year: '', month: '' });
  const [categoriesInv, setCategoriesInv] = useState([]);
  const [secteursInv,   setSecteursInv]   = useState([]);
  const [platYear,   setPlatYear]   = useState(String(new Date().getFullYear()));
  const [modalOpen,  setModalOpen]  = useState(false);
  const [editingId,  setEditingId]  = useState(null);
  const [form,       setForm]       = useState(empty);
  const [err,        setErr]        = useState(null);
  const [loading,    setLoading]    = useState(false);
  const [deleteConfirm, setDeleteConfirm] = useState(null);
  const [openMenu, setOpenMenu] = useState(null);

  /* ── Chargement (sans filtre — filtrage côté client) ── */
  const load = async () => {
    if (!activeId && activeView !== 'all') return;
    setLoading(true);
    setAllRows([]);
    try {
      const scopeParams = activeView === 'all' ? { scope: 'all' } : {};
      const [r, p, comptes, rembs, reinvests, catInv, sectInv] = await Promise.all([
        api.get('/investissements', scopeParams),
        api.get('/plateformes'),
        api.get('/investissements/comptes-courants'),
        api.get('/remboursements', scopeParams),
        api.get('/reinvestissements', { scope: 'all' }),
        api.get('/categories-inv'),
        api.get('/secteurs-inv'),
      ]);
      setAllRows(r);
      setAllRembs(rembs);
      setAllReinvests(reinvests);
      setPlats(p);
      setComptesCourants(comptes);
      setCategoriesInv(catInv);
      setSecteursInv(sectInv);
      platsRef.current = p;
    } finally { setLoading(false); }
  };

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

  // Charge les comptes du détenteur courant dès que l'investisseur du formulaire change
  useEffect(() => {
    if (!form.investisseur_id || !modalOpen) { setComptesInvestisseur([]); return; }
    api.get(`/investissements/comptes-par-investisseur/${form.investisseur_id}`)
      .then(comptes => {
        setComptesInvestisseur(comptes);
        if (form.methode_remboursement === 'compte_courant' && !form.compte_id) {
          const def = comptes.find(c => c.type === 'compte_courant') ?? comptes[0];
          if (def) setForm(f => ({ ...f, compte_id: String(def.id), nom_compte_courant: def.nom }));
        }
      })
      .catch(() => setComptesInvestisseur([]));
  }, [form.investisseur_id, modalOpen]); /* eslint-disable-next-line */

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

  /* ── Années disponibles (pour le sélecteur) ── */
  const years = useMemo(() =>
    [...new Set(allRows.map(r => r.date_souscription?.slice(0, 4)).filter(Boolean))].sort().reverse(),
    [allRows]);

  /* ── Filtrage côté client ── */
  const rows = useMemo(() => {
    return allRows.filter(r => {
      if (filter.statut === 'defaut') {
        if (!['en_retard', 'procedure'].includes(r.statut)) return false;
      } else if (filter.statut && r.statut !== filter.statut) {
        return false;
      }
      if (filter.plateforme_id && String(r.plateforme_id) !== String(filter.plateforme_id)) return false;
      if (filter.categorie_inv_id && !(r.categories_inv || []).some(c => String(c.id) === String(filter.categorie_inv_id))) return false;
      if (filter.secteur_inv_id   && !(r.secteurs_inv   || []).some(s => String(s.id) === String(filter.secteur_inv_id)))   return false;
      if (filter.year  && r.date_souscription?.slice(0, 4) !== filter.year) return false;
      if (filter.month && r.date_souscription?.slice(5, 7) !== filter.month.padStart(2, '0')) return false;
      return true;
    });
  }, [allRows, filter]);

  /* ── Pagination investissements ── */
  const {
    pagedItems: pagedRows, page: invPage, setPage: setInvPage,
    pageSize: invPageSize, setPageSize: setInvPageSize,
    totalPages: invTotalPages, totalItems: invTotalItems, PAGE_SIZES,
  } = usePagination(rows, 'cl_pagesize_inv', [filter]);

  /* ── Helper : investissement actif au 31/12 de platYear ─────────
   * Cohérent avec capitalMensuel du dashboard (test sur le mois de décembre) :
   *  - souscrit avant la fin de l'année
   *  - ET (statut encore actif aujourd'hui OU date de clôture ≥ 1er déc.)
   * ──────────────────────────────────────────────────────────────── */
  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 = platYear) => {
    if (!yr) return true;
    const cutoff  = `${yr}-12-31`;
    const decStart = `${yr}-12-01`;
    if (r.date_souscription > cutoff) return false;   // pas encore souscrit
    const ACTIVE = ['en_cours', 'en_retard', 'procedure'];
    if (ACTIVE.includes(r.statut)) return true;       // encore actif aujourd'hui
    const fin = r.date_cible ?? lastRembDateMap[r.id] ?? null;
    return !!fin && fin >= decStart;                  // clôturé mais actif en décembre
  };

  /* ── kpiRows : plateforme + année sélectionnées, sans filtre statut ── */
  /* (le filtre statut ne doit pas affecter les chiffres des autres KPIs) */
  const kpiRows = useMemo(() =>
    allRows.filter(r => {
      if (filter.plateforme_id && String(r.plateforme_id) !== String(filter.plateforme_id)) return false;
      if (platYear && !isActiveAtEndOfYear(r)) return false;
      return true;
    }),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [allRows, filter.plateforme_id, platYear, lastRembDateMap]
  );

  /* ── Agrégats remboursements filtrés par coupure (platYear), par investissement ── */
  const rembParInv = useMemo(() => {
    const cutoff = platYear ? `${platYear}-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) continue;
      if (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, platYear]);

  // Alias pour rétrocompatibilité
  const capRembParInv = useMemo(() =>
    Object.fromEntries(Object.entries(rembParInv).map(([id, v]) => [id, v.capital])),
    [rembParInv]);

  /* ── Réinvestissements cumulés par investissement, filtrés par coupure ── */
  const reinvestCumulParInv = useMemo(() => {
    const cutoff = platYear ? `${platYear}-12-31` : null;
    const map = {};
    for (const rv of allReinvests) {
      const d = rv.date_reinvestissement?.slice(0, 10);
      if (!d) continue;
      if (cutoff && d > cutoff) continue;
      map[rv.investissement_id] = (map[rv.investissement_id] || 0) + (rv.montant || 0);
    }
    return map;
  }, [allReinvests, platYear]);

  /* ── Totaux KPI (depuis kpiRows — réagit à plateforme + année) ── */
  const totals = useMemo(() => kpiRows.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 }), [kpiRows, capRembParInv, rembParInv, reinvestCumulParInv]);

  /* ── Totaux KPI année N-1 (pour TrendBadge) ── */
  const prevTotals = useMemo(() => {
    const effectiveYear = platYear || String(new Date().getFullYear());
    const prevYear = String(Number(effectiveYear) - 1);
    const cutoff   = `${prevYear}-12-31`;
    // Remboursements cumulés jusqu'à fin de l'année précédente
    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 prevReinvestCumul = {};
    for (const rv of allReinvests) {
      const d = rv.date_reinvestissement?.slice(0, 10);
      if (!d || d > cutoff) continue;
      prevReinvestCumul[rv.investissement_id] = (prevReinvestCumul[rv.investissement_id] || 0) + (rv.montant || 0);
    }
    const prevRows = allRows.filter(r => {
      if (filter.plateforme_id && String(r.plateforme_id) !== String(filter.plateforme_id)) return false;
      return isActiveAtEndOfYear(r, prevYear);
    });
    return prevRows.reduce((acc, r) => {
      const capInv  = r.montant_investi + (prevReinvestCumul[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
  }, [platYear, allRows, allRembs, allReinvests, filter.plateforme_id, lastRembDateMap]);

  /* ── Répartition par plateforme (filtrée par platYear si défini) ── */
  const platData = useMemo(() => {
    const src = platYear
      ? allRows.filter(r => isActiveAtEndOfYear(r))
      : allRows;
    const totalInvesti = src.reduce((s, r) => s + r.montant_investi + (reinvestCumulParInv[r.id] || 0), 0);
    const byPlat = {};
    for (const r of src) {
      if (!byPlat[r.plateforme_id]) {
        byPlat[r.plateforme_id] = {
          plateforme_id: r.plateforme_id,
          nom: r.plateforme_nom,
          detenteur_nom: r.plateforme_detenteur_nom || null,
          count: 0, investi: 0, cap_remb: 0,
          int_perc: 0, int_perc_net: 0, encours: 0, defaut: 0,
        };
      }
      const p = byPlat[r.plateforme_id];
      const capInv = r.montant_investi + (reinvestCumulParInv[r.id] || 0);
      const capRemb = capRembParInv[r.id] || 0;
      p.count++;
      p.investi      += capInv;
      p.cap_remb     += capRemb;
      p.int_perc     += rembParInv[r.id]?.interets_bruts || 0;
      p.int_perc_net += rembParInv[r.id]?.interets_nets  || 0;
      const capRestant = Math.max(0, capInv - capRemb);
      // Sans filtre année : les prêts remboursés ont capRestant=0 → pas d'impact
      // Avec filtre année  : on veut le capital déployé à la coupure, quel que soit le statut actuel
      p.encours += capRestant;
      if (['en_retard', 'procedure'].includes(r.statut)) p.defaut += capRestant;
    }
    return Object.values(byPlat)
      .sort((a, b) => b.investi - a.investi)
      .map(p => ({ ...p, poids: totalInvesti > 0 ? (p.investi / totalInvesti) * 100 : 0 }));
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [allRows, platYear, capRembParInv, rembParInv, reinvestCumulParInv, lastRembDateMap]);

  /* ── Totaux du tableau plateformes ── */
  const platTotals = useMemo(() => platData.reduce((acc, p) => {
    acc.count        += p.count;
    acc.investi      += p.investi;
    acc.encours      += p.encours;
    acc.cap_remb     += p.cap_remb;
    acc.int_perc     += p.int_perc;
    acc.int_perc_net += p.int_perc_net;
    return acc;
  }, { count: 0, investi: 0, encours: 0, cap_remb: 0, int_perc: 0, int_perc_net: 0 }), [platData]);

  /* ── Données graphiques : filtrées par statut + plateforme + année ── */
  const chartRows = useMemo(() => {
    return allRows.filter(r => {
      if (filter.statut === 'defaut') {
        if (!['en_retard', 'procedure'].includes(r.statut)) return false;
      } else if (filter.statut && r.statut !== filter.statut) {
        return false;
      }
      if (filter.plateforme_id && String(r.plateforme_id) !== String(filter.plateforme_id)) return false;
      if (platYear && !isActiveAtEndOfYear(r)) return false;
      return true;
    });
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [allRows, filter.statut, filter.plateforme_id, platYear, lastRembDateMap]);

  /* ── Données pour DistributionChart — capital restant dû à la coupure, par plateforme ── */
  const invDistRows = useMemo(() =>
    chartRows
      .map(r => {
        const capInv = r.montant_investi + (reinvestCumulParInv[r.id] || 0);
        const capRemb = capRembParInv[r.id] || 0;
        const capRestant = Math.max(0, capInv - capRemb);
        return { plateforme_nom: r.plateforme_nom, montant: capRestant };
      })
      .filter(r => r.montant > 0),
    [chartRows, capRembParInv, reinvestCumulParInv]);

  /* ── Investisseur par défaut ── */
  const defaultInvestisseurId = () => {
    if (activeView === 'all') {
      const principal = investisseurs.find(i => i.is_principal);
      return String((principal || investisseurs[0])?.id || '');
    }
    return String(activeId || '');
  };

  /** Retourne l'investisseur_id de la plateforme, ou le défaut si absent */
  const investisseurForPlat = (platId) => {
    const plat = plats.find(p => String(p.id) === String(platId));
    return plat?.investisseur_id ? String(plat.investisseur_id) : defaultInvestisseurId();
  };

  /* ── Ouverture auto depuis le bouton global ── */
  const pendingNew = useRef(false);
  useEffect(() => {
    if (new URLSearchParams(search).get('new') !== '1') return;
    navigate('/investissements', { replace: true });
    if (plats.length > 0) {
      setEditingId(null);
      setForm({ ...empty });
      setErr(null);
      setModalOpen(true);
    } else {
      pendingNew.current = true;
    }
  }, [search]); /* eslint-disable-next-line */

  useEffect(() => {
    if (!pendingNew.current || !plats.length) return;
    pendingNew.current = false;
    setEditingId(null);
    setForm({ ...empty });
    setErr(null);
    setModalOpen(true);
  }, [plats]); /* eslint-disable-next-line */

  /* ── CRUD ── */
  const openNew = () => {
    setEditingId(null);
    setForm({ ...empty });
    setErr(null);
    setModalOpen(true);
  };

  const openEdit = async (row) => {
    setEditingId(row.id);
    const plat = plats.find(p => p.id === row.plateforme_id);
    const platMethode = plat?.methode_remboursement;
    const resolvedMethode = platMethode && platMethode !== 'choix_investisseur'
      ? platMethode
      : (row.methode_remboursement || '');
    setForm({
      investisseur_id: String(row.investisseur_id || ''),
      plateforme_id: row.plateforme_id,
      nom_projet: row.nom_projet,
      emetteur: row.emetteur || '',
      date_souscription: row.date_souscription,
      date_premiere_echeance: row.date_premiere_echeance || '',
      date_cible: row.date_cible || '',
      montant_investi: row.montant_investi,
      taux_interet: row.taux_interet ?? '',
      duree_mois: row.duree_mois ?? '',
      type_remb: row.type_remb || 'in_fine',
      freq_interets: row.freq_interets || 'mensuel',
      statut: row.statut,
      reference: row.reference || '',
      notes: row.notes || '',
      echeance_fin_de_mois: !!row.echeance_fin_de_mois,
      methode_remboursement: resolvedMethode,
      nom_compte_courant: row.nom_compte_courant || '',
      compte_id: row.compte_id || '',
      pays_exposition: row.pays_exposition || 'FR',
      categories_inv_ids: (row.categories_inv || []).map(c => c.id),
      secteurs_inv_ids:   (row.secteurs_inv   || []).map(s => s.id),
    });
    setErr(null);
    setModalOpen(true);
  };

  const close = () => { setModalOpen(false); setEditingId(null); setForm(empty); setErr(null); };

  const submit = async (e) => {
    e?.preventDefault?.();
    setErr(null);
    try {
      // La case "Dernier jour du mois" n'est pertinente que pour in_fine / différé
      // avec une première échéance après le 27. On la force à 0 sinon.
      const showFinDeMois = (form.type_remb === 'in_fine' || form.type_remb === 'differe')
        && dayOfMonth(form.date_premiere_echeance) > 27;

      // Validation date d'échéance pour les prêts différés
      if (form.type_remb === 'differe' && !form.date_premiere_echeance) {
        setErr("La date d'échéance est requise pour un prêt différé. Vérifiez que la durée et la date de souscription sont renseignées.");
        return;
      }

      const payload = {
        investisseur_id: Number(form.investisseur_id) || undefined,
        plateforme_id: Number(form.plateforme_id),
        nom_projet: form.nom_projet,
        emetteur: form.emetteur || undefined,
        date_souscription: form.date_souscription,
        date_premiere_echeance: form.date_premiere_echeance || '',
        date_cible: form.date_cible || '',
        montant_investi: Number(form.montant_investi),
        taux_interet: form.taux_interet === '' ? undefined : Number(form.taux_interet),
        duree_mois: form.duree_mois === '' ? undefined : Number(form.duree_mois),
        type_remb: form.type_remb || '',
        freq_interets: form.type_remb === 'differe' ? 'in_fine' : (form.freq_interets || 'mensuel'),
        statut: form.statut,
        reference: form.reference || undefined,
        notes: form.notes || undefined,
        echeance_fin_de_mois: (showFinDeMois && form.echeance_fin_de_mois) ? 1 : 0,
        methode_remboursement: form.methode_remboursement || null,
        nom_compte_courant: form.methode_remboursement === 'compte_courant' ? (form.nom_compte_courant || null) : null,
        compte_id: form.methode_remboursement === 'compte_courant' && form.compte_id ? Number(form.compte_id) : null,
        pays_exposition: form.pays_exposition || 'FR',
      };
      if (editingId) {
        await api.put(`/investissements/${editingId}`, payload);
        await Promise.all([
          api.put(`/investissements/${editingId}/categories-inv`, { ids: form.categories_inv_ids || [] }),
          api.put(`/investissements/${editingId}/secteurs-inv`,   { ids: form.secteurs_inv_ids   || [] }),
        ]);
        close(); await load();
      } else {
        const created = await api.post('/investissements', payload);
        await Promise.all([
          api.put(`/investissements/${created.id}/categories-inv`, { ids: form.categories_inv_ids || [] }),
          api.put(`/investissements/${created.id}/secteurs-inv`,   { ids: form.secteurs_inv_ids   || [] }),
        ]);
        close();
        navigate(`/investissements/${created.id}`);
      }
    } catch (e) { setErr(e.message); }
  };

  const onDelete = (row) => {
    setDeleteConfirm({
      message: `Supprimer "${row.nom_projet}" ? Toutes les échéances liées seront effacées.`,
      onConfirm: async () => {
        await api.del(`/investissements/${row.id}`);
        setDeleteConfirm(null);
        load();
      },
    });
  };

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

  const hasFilter = !!(filter.statut || filter.plateforme_id || filter.categorie_inv_id || filter.secteur_inv_id || filter.year || filter.month);
  const netMode   = displayMode === 'net';
  const clearFilter = () => setFilter({ statut: '', plateforme_id: '', categorie_inv_id: '', secteur_inv_id: '', year: '', month: '' });
  const multiDetenteur = new Set(plats.map(p => p.investisseur_id)).size > 1;

  if (!loading && plats.length === 0) return (
    <>
      <div className="topbar"><h2>Investissements</h2></div>
      <EmptyState />
    </>
  );
  return (
    <>
      <div className="topbar">
        <h2><PageIcon name="investissement" />Investissements</h2>
        {hasFilter && (
          <button className="dr-clear-btn" onClick={clearFilter}>
            ✕ Effacer les filtres
          </button>
        )}
      </div>

      {/* ── Graphiques ── */}
      {!listFocused && <div className="charts-row">
        <InvChart rows={chartRows} remboursements={allRembs} reinvestissements={allReinvests} platYear={platYear} />
        <DistributionChart rows={invDistRows} />
      </div>}

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

        {/* 1 — Capital investi */}
        <div
          className={`kpi dr-kpi-clickable${filter.statut === 'en_cours' ? ' dr-kpi-active dr-kpi-active-success' : ''}`}
          onClick={() => {
            setFilter(f => ({ ...f, statut: f.statut === 'en_cours' ? '' : 'en_cours' }));
            setActiveTab('investissements');
          }}
          title="Filtrer les investissements en cours"
        >
          <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>
            {prevTotals && <TrendBadge current={totals.encours} prev={prevTotals.encours} />}
          </div>
          {prevTotals && <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>{fmtEUR(prevTotals.encours)} en {platYear ? Number(platYear) - 1 : new Date().getFullYear() - 1}</div>}
        </div>

        {/* 2 — Investissements à risque */}
        <div
          className={`kpi${totals.defaut > 0 ? ' dr-kpi-clickable' : ''}${filter.statut === 'defaut' ? ' dr-kpi-active dr-kpi-active-danger' : ''}`}
          onClick={() => {
            if (totals.defaut === 0) return;
            setFilter(f => ({ ...f, statut: f.statut === 'defaut' ? '' : 'defaut' }));
            setActiveTab('investissements');
          }}
          title={totals.defaut > 0 ? 'Filtrer les investissements en retard / procédure' : undefined}
          style={totals.defaut > 0 ? { cursor: 'pointer' } : {}}
        >
          <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>
            {prevTotals && totals.defaut > 0 && <TrendBadge current={totals.defaut} prev={prevTotals.defaut} invert={true} />}
          </div>
          {prevTotals && <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>{fmtEUR(prevTotals.defaut)} en {platYear ? Number(platYear) - 1 : new Date().getFullYear() - 1}</div>}
        </div>

        {/* 3 — Investissements depuis le début */}
        <div
          className={`kpi${hasFilter ? ' dr-kpi-clickable dr-kpi-active dr-kpi-active-neutral' : ''}`}
          onClick={() => hasFilter && clearFilter()}
          title={hasFilter ? 'Effacer les filtres' : undefined}
          style={hasFilter ? { cursor: 'pointer' } : {}}
        >
          <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>
            {prevTotals && <TrendBadge current={totals.investi} prev={prevTotals.investi} />}
          </div>
          {prevTotals && <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>{fmtEUR(prevTotals.investi)} en {platYear ? Number(platYear) - 1 : new Date().getFullYear() - 1}</div>}
        </div>

        {/* 4 — Investissements remboursés */}
        <div className="kpi">
          <div className="label">Investissements remboursés</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>
            {prevTotals && <TrendBadge current={totals.cap_remb} prev={prevTotals.cap_remb} />}
          </div>
          {prevTotals && <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>{fmtEUR(prevTotals.cap_remb)} en {platYear ? Number(platYear) - 1 : new Date().getFullYear() - 1}</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>
            {prevTotals && <TrendBadge current={netMode ? totals.int_perc_net : totals.int_perc} prev={netMode ? prevTotals.int_perc_net : prevTotals.int_perc} />}
          </div>
          {prevTotals && <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>{fmtEUR(netMode ? prevTotals.int_perc_net : prevTotals.int_perc)} en {platYear ? Number(platYear) - 1 : new Date().getFullYear() - 1}</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 === 'investissements' ? ' active' : ''}`}
          onClick={() => setActiveTab('investissements')}>Investissements</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
                {platYear && (
                  <span style={{ marginLeft: 8 }}>pour l'année {platYear}</span>
                )}
              </h3>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                {/* Sélecteur d'année */}
                <select
                  value={platYear}
                  onChange={e => setPlatYear(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>
                <button
                  type="button"
                  className="icon-btn"
                  title={listFocused ? 'Réduire' : 'Agrandir'}
                  onClick={() => {
                    const next = !listFocused;
                    setListFocused(next);
                    setInvPageSize(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={platData.length === 0}
                  onCSV={() => dlBlob(platToCSV(platData), `plateformes-investissements${platYear ? '-' + platYear : ''}.csv`, 'text/csv;charset=utf-8')}
                  onXLS={() => dlBlob(platToXLS(platData), `plateformes-investissements${platYear ? '-' + platYear : ''}.xlsx`, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')}
                  onJSON={() => dlBlob(platToJSON(platData), `plateformes-investissements${platYear ? '-' + platYear : ''}.json`, 'application/json')}
                />
              </div>
            </div>

            {!allRows.length && loading ? (
              <div className="text-muted" style={{ padding: '12px 0' }}>Chargement…</div>
            ) : (
              <table>
                <thead>
                  <tr>
                    <th>Plateforme</th>
                    <th>Détenteur</th>
                    <th className="num">Projets</th>
                    <th className="num">Montant investi</th>
                    <th className="num">Capital investi</th>
                    <th className="num">Investissements remboursés</th>
                    <th className="num">Intérêts ({netMode ? 'Net' : 'Brut'})</th>
                    <th className="num">Poids</th>
                    <th style={{ width: 28 }}></th>
                  </tr>
                </thead>
                <tbody>
                  {platData.length === 0 && (
                    <tr><td colSpan={9} className="text-muted" style={{ textAlign: 'center', padding: 24 }}>
                      Aucun investissement
                    </td></tr>
                  )}
                  {platData.map(p => {
                    const isActive = String(filter.plateforme_id) === String(p.plateforme_id);
                    return (
                      <tr key={p.plateforme_id}
                        className={`dr-row${isActive ? ' dr-row-selected' : ''}`}
                        style={{ cursor: 'pointer' }}
                        onClick={() => {
                          setFilter(f => ({ ...f, plateforme_id: isActive ? '' : String(p.plateforme_id) }));
                          if (!isActive) setActiveTab('investissements');
                        }}>
                        <td>
                          <span style={{ fontWeight: isActive ? 600 : undefined }}>{p.nom}</span>
                          {p.defaut > 0 && (
                            <span style={{
                              marginLeft: 6, fontSize: 10, fontWeight: 600,
                              padding: '1px 5px', borderRadius: 3,
                              background: 'color-mix(in srgb, var(--danger) 15%, transparent)',
                              color: 'var(--danger)', verticalAlign: 'middle',
                            }}>!</span>
                          )}
                        </td>
                        <td className="text-muted" style={{ fontSize: 'var(--fs-sm)' }}>{p.detenteur_nom || '—'}</td>
                        <td className="num">{p.count}</td>
                        <td className="num">{fmtEUR(p.investi)}</td>
                        <td className="num">{fmtEUR(p.encours)}</td>
                        <td className="num">{fmtEUR(p.cap_remb)}</td>
                        <td className="num">{fmtEUR(netMode ? p.int_perc_net : p.int_perc)}</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, p.poids)}%`, height: '100%', background: 'var(--primary)', borderRadius: 3 }} />
                            </div>
                            <span style={{ minWidth: 36, textAlign: 'right', fontSize: 'var(--fs-sm)' }}>
                              {p.poids.toFixed(1)} %
                            </span>
                          </div>
                        </td>
                        <td style={{ textAlign: 'center', color: 'var(--text-muted)', fontSize: 11 }}>
                          {isActive ? '✕' : ''}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
                {platData.length > 1 && (
                  <tfoot>
                    <tr style={{
                      borderTop: '2px solid var(--border)',
                      fontWeight: 700,
                      background: 'var(--surface-2)',
                    }}>
                      <td style={{ padding: '10px 12px', color: 'var(--text-muted)', fontSize: 'var(--fs-sm)', fontWeight: 600 }}>
                        Total — {platData.length} plateformes
                      </td>
                      <td />
                      <td className="num" style={{ padding: '10px 12px' }}>{platTotals.count}</td>
                      <td className="num" style={{ padding: '10px 12px' }}>{fmtEUR(platTotals.investi)}</td>
                      <td className="num" style={{ padding: '10px 12px' }}>{fmtEUR(platTotals.encours)}</td>
                      <td className="num" style={{ padding: '10px 12px' }}>{fmtEUR(platTotals.cap_remb)}</td>
                      <td className="num" style={{ padding: '10px 12px' }}>
                        {fmtEUR(netMode ? platTotals.int_perc_net : platTotals.int_perc)}
                      </td>
                      <td className="num" style={{ padding: '10px 12px' }}>
                        <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' }}>
            <CapitalMensuelTable
            allRows={allRows}
            allRembs={allRembs}
            allReinvests={allReinvests}
            plats={plats}
            expandButton={
            <button
              type="button"
              className="icon-btn"
              title={listFocused ? 'Réduire' : 'Agrandir'}
              style={{ marginLeft: 4 }}
              onClick={() => { const next = !listFocused; setListFocused(next); setInvPageSize(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>
      )}

      {/* ====== ONGLET INVESTISSEMENTS ====== */}
      {activeTab === 'investissements' && (
        <div style={{ padding: '0 24px' }}>
          <div className="card">

            {/* En-tête + export */}
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
              <h3 style={{ margin: 0 }}>
                Liste des investissements
                {rows.length !== allRows.length && (
                  <span style={{ marginLeft: 8, fontSize: 'var(--fs-xs)', fontWeight: 400, color: 'var(--text-muted)' }}>
                    {rows.length} / {allRows.length}
                  </span>
                )}
              </h3>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                <button
                  type="button"
                  className="icon-btn"
                  title={listFocused ? 'Réduire la liste' : 'Agrandir la liste'}
                  onClick={() => {
                    const next = !listFocused;
                    setListFocused(next);
                    setActiveTab('investissements');
                    setInvPageSize(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={rows.length === 0}
                  onCSV={() => dlBlob(invToCSV(rows), 'investissements.csv', 'text/csv;charset=utf-8')}
                  onXLS={() => dlBlob(invToXLS(rows), 'investissements.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')}
                  onJSON={() => dlBlob(invToJSON(rows), 'investissements.json', 'application/json')}
                />
              </div>
            </div>

            {/* Filtres */}
            <div className="row" style={{ marginBottom: 12, gap: 8 }}>
              <div style={{ flex: 1, minWidth: 110 }}>
                <label>Statut</label>
                <select value={filter.statut === 'defaut' ? '' : filter.statut}
                  onChange={e => setFilter(f => ({ ...f, statut: e.target.value }))}>
                  <option value="">Tous</option>
                  <option value="en_cours">En cours</option>
                  <option value="rembourse">Remboursé</option>
                  <option value="en_retard">En retard</option>
                  <option value="procedure">Procédure</option>
                  <option value="cloture">Clôturé</option>
                </select>
              </div>
              <div style={{ flex: 1, minWidth: 120 }}>
                <label>Plateforme</label>
                <select value={filter.plateforme_id}
                  onChange={e => setFilter(f => ({ ...f, plateforme_id: e.target.value }))}>
                  <option value="">Toutes</option>
                  {plats.map(p => <option key={p.id} value={p.id}>{p.nom}{multiDetenteur && p.investisseur_nom ? ` — ${p.investisseur_nom}` : ''}</option>)}
                </select>
              </div>
              <div style={{ flex: 1, minWidth: 130 }}>
                <label>Catégorie</label>
                <select value={filter.categorie_inv_id}
                  onChange={e => setFilter(f => ({ ...f, categorie_inv_id: e.target.value }))}>
                  <option value="">Toutes</option>
                  {categoriesInv.map(c => <option key={c.id} value={c.id}>{c.nom}</option>)}
                </select>
              </div>
              <div style={{ flex: 1, minWidth: 130 }}>
                <label>Secteur</label>
                <select value={filter.secteur_inv_id}
                  onChange={e => setFilter(f => ({ ...f, secteur_inv_id: e.target.value }))}>
                  <option value="">Tous</option>
                  {secteursInv.map(s => <option key={s.id} value={s.id}>{s.nom}</option>)}
                </select>
              </div>
              <div style={{ flex: 1, minWidth: 90 }}>
                <label>Année</label>
                <select value={filter.year}
                  onChange={e => setFilter(f => ({ ...f, year: e.target.value }))}>
                  <option value="">Toutes</option>
                  {years.map(y => <option key={y} value={y}>{y}</option>)}
                </select>
              </div>
              <div style={{ flex: 1, minWidth: 110 }}>
                <label>Mois</label>
                <select value={filter.month}
                  onChange={e => setFilter(f => ({ ...f, 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>
              {filter.statut === 'defaut' && (
                <div style={{ display: 'flex', alignItems: 'flex-end' }}>
                  <span className="badge en_retard" style={{ marginBottom: 2, whiteSpace: 'nowrap' }}>
                    En retard + Procédure
                  </span>
                </div>
              )}
            </div>

            <table style={{ cursor: 'pointer' }}>
              <thead>
                <tr>
                  <th>Date</th><th>Projet</th><th>Plateforme</th><th>Détenteur</th>
                  <th className="num">Montant</th><th className="num">Taux</th>
                  <th className="num">Durée</th><th>Type remb.</th>
                  <th className="num">Inv. remboursés</th><th className="num">Cap. restant dû</th>
                  <th className="num">Int. ({netMode ? 'Net' : 'Brut'})</th>
                  <th>Statut</th>
                  <th style={{ width: 36 }}></th>
                </tr>
              </thead>
              <tbody>
                {rows.length === 0 && (
                  <tr><td colSpan={13} className="text-muted" style={{ textAlign: 'center', padding: 24 }}>
                    {loading ? 'Chargement…' : 'Aucun investissement'}
                  </td></tr>
                )}
                {pagedRows.map(r => {
                  const capInv     = r.capital_total ?? r.montant_investi;
                  const capRestant = Math.max(0, capInv - (r.capital_rembourse || 0));
                  return (
                    <tr key={r.id}
                      onClick={() => navigate(`/investissements/${r.id}`)}
                      style={{ cursor: 'pointer' }}
                      onMouseEnter={e => e.currentTarget.style.opacity = '0.8'}
                      onMouseLeave={e => e.currentTarget.style.opacity = '1'}
                    >
                      <td>{fmtDate(r.date_souscription)}</td>
                      <td>
                        <strong>{r.nom_projet}</strong>
                        {r.emetteur && <div className="text-muted" style={{ fontSize: 11 }}>{r.emetteur}</div>}
                      </td>
                      <td>{r.plateforme_nom}</td>
                      <td className="text-muted" style={{ fontSize: 'var(--fs-sm)' }}>{r.plateforme_detenteur_nom || '—'}</td>
                      <td className="num">{fmtEUR(capInv)}</td>
                      <td className="num">{r.taux_interet != null ? fmtPct(r.taux_interet) : '—'}</td>
                      <td className="num">{r.duree_mois ? `${r.duree_mois} m.` : '—'}</td>
                      <td className="text-muted" style={{ fontSize: 11 }}>
                        {TYPE_REMB_LABELS[r.type_remb] || '—'}
                        {r.freq_interets && r.type_remb !== 'differe' ? ` · ${r.freq_interets}` : ''}
                      </td>
                      <td className="num">{fmtEUR(r.capital_rembourse || 0)}</td>
                      <td className="num" style={{ color: capRestant === 0 ? 'var(--success)' : undefined }}>
                        {fmtEUR(capRestant)}
                      </td>
                      <td className="num">{fmtEUR(netMode ? (r.interets_nets_total || 0) : (r.interets_percus || 0))}</td>
                      <td><span className={`badge ${r.statut}`}>{fmtStatut(r.statut)}</span></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={invPage} setPage={setInvPage}
              pageSize={invPageSize} setPageSize={setInvPageSize}
              totalPages={invTotalPages} totalItems={invTotalItems}
              PAGE_SIZES={PAGE_SIZES}
            />
          </div>
        </div>
      )}

      {/* ── Modal création / édition ── */}
      <Modal
        open={modalOpen}
        title={editingId ? 'Modifier l\'investissement' : 'Nouvel investissement'}
        onClose={close}
        width={720}
        footer={
          <>
            <button onClick={close}>Annuler</button>
            <button className="primary" onClick={submit}>{editingId ? 'Enregistrer' : 'Créer'}</button>
          </>
        }
      >
        <form onSubmit={submit}>
          {err && <div className="error">{err}</div>}
          <div className="form-grid">
            <div>
              <label>Plateforme *</label>
              <select required value={form.plateforme_id} onChange={e => {
                const platId = e.target.value;
                const platObj = plats.find(p => String(p.id) === String(platId));
                const platMethode = platObj?.methode_remboursement;
                const newMethode = platMethode === 'choix_investisseur' ? '' : (platMethode || '');
                // Pré-remplir catégories/secteurs depuis la plateforme
                if (platId) {
                  Promise.all([
                    api.get(`/plateformes/${platId}/categories-inv`).catch(() => []),
                    api.get(`/plateformes/${platId}/secteurs-inv`).catch(() => []),
                  ]).then(([platCats, platSects]) => {
                    setForm(f => ({ ...f,
                      plateforme_id: platId,
                      investisseur_id: investisseurForPlat(platId),
                      methode_remboursement: newMethode, compte_id: '',
                      categories_inv_ids: platCats.map(c => c.id),
                      secteurs_inv_ids:   platSects.map(s => s.id),
                    }));
                  });
                } else {
                  setForm(f => ({ ...f, plateforme_id: platId, investisseur_id: investisseurForPlat(platId), methode_remboursement: newMethode, compte_id: '', categories_inv_ids: [], secteurs_inv_ids: [] }));
                }
              }}>
                <option value="">—</option>
                {plats.map(p => <option key={p.id} value={p.id}>{p.nom}{multiDetenteur && p.investisseur_nom ? ` — ${p.investisseur_nom}` : ''}</option>)}
              </select>
            </div>
            {(() => {
              const platMethode = plats.find(p => String(p.id) === String(form.plateforme_id))?.methode_remboursement;
              if (!platMethode) return null;
              if (platMethode === 'choix_investisseur') return (
                <div>
                  <label>Méthode de remboursement</label>
                  <select value={form.methode_remboursement} onChange={e => {
                    const methode = e.target.value;
                    const defaultCompte = methode === 'compte_courant'
                      ? (comptesInvestisseur.find(c => c.type === 'compte_courant') ?? comptesInvestisseur[0])
                      : null;
                    setForm({ ...form, methode_remboursement: methode, nom_compte_courant: defaultCompte?.nom || '', compte_id: String(defaultCompte?.id || '') });
                  }}>
                    <option value="">— Non renseignée —</option>
                    <option value="portefeuille">Porte-monnaie de la plateforme</option>
                    <option value="compte_courant">Compte courant de l'investisseur</option>
                  </select>
                </div>
              );
              // Méthode fixée par la plateforme — lecture seule
              return (
                <div>
                  <label>Méthode de remboursement</label>
                  <input readOnly value={platMethode === 'compte_courant' ? "Compte courant de l'investisseur" : 'Porte-monnaie de la plateforme'}
                    style={{ background: 'var(--surface-2)', color: 'var(--text-muted)', cursor: 'default' }} />
                </div>
              );
            })()}
            {form.methode_remboursement === 'compte_courant' && (
              <div>
                <label>Compte de réception *</label>
                {comptesInvestisseur.length > 0 ? (
                  <select
                    required
                    value={form.compte_id}
                    onChange={e => {
                      const c = comptesInvestisseur.find(c => String(c.id) === e.target.value);
                      setForm({ ...form, compte_id: e.target.value, nom_compte_courant: c?.nom || '' });
                    }}
                  >
                    <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 pour ce détenteur. <a href="/settings?section=comptes" target="_blank" rel="noreferrer">Créer un compte →</a>
                  </p>
                )}
              </div>
            )}
            {/* Détenteur auto-déduit de la plateforme — champ masqué */}
            <input type="hidden" value={form.investisseur_id} />

            <div style={{ gridColumn: 'span 2' }}>
              <label>Nom du projet *</label>
              <input required value={form.nom_projet} onChange={e => setForm({ ...form, nom_projet: e.target.value })} />
            </div>
            <div>
              <label>Montant investi (€) *</label>
              <input type="number" step="0.01" min="0" required value={form.montant_investi}
                onChange={e => setForm({ ...form, montant_investi: e.target.value })} />
            </div>
            <div>
              <label>Taux annuel (%) *</label>
              <input type="number" step="0.01" required value={form.taux_interet}
                onChange={e => setForm({ ...form, taux_interet: e.target.value })} />
            </div>
            <div>
              <label>Durée (mois) *</label>
              <input type="number" min="0" required value={form.duree_mois} onChange={e => {
                const duree = e.target.value;
                const next = { ...form, duree_mois: duree };
                if (duree) {
                  if (form.type_remb === 'differe' && form.date_souscription) {
                    const tempDpe = addMonthsFE(form.date_souscription, 1);
                    const cible = addMonthsFE(tempDpe, Number(duree) - 1);
                    next.date_premiere_echeance = cible;
                    next.date_cible = cible;
                  } else if (form.date_premiere_echeance) {
                    next.date_cible = addMonthsFE(form.date_premiere_echeance, Number(duree) - 1);
                  }
                }
                setForm(next);
              }} />
            </div>
            <div>
              <label>Type de prêt</label>
              <select value={form.type_remb} onChange={e => {
                const t = e.target.value;
                const next = {
                  ...form, type_remb: t,
                  freq_interets: t === 'differe' ? 'in_fine' : (form.freq_interets === 'in_fine' ? 'mensuel' : form.freq_interets),
                };
                if (t === 'differe') {
                  // Recalculer la date d'échéance depuis souscription+durée (prioritaire sur l'ancienne valeur)
                  if (form.date_souscription && form.duree_mois) {
                    const dpe = addMonthsFE(form.date_souscription, 1);
                    const cible = addMonthsFE(dpe, Number(form.duree_mois) - 1);
                    next.date_premiere_echeance = cible;
                    next.date_cible = cible;
                  } else if (form.date_premiere_echeance) {
                    next.date_cible = form.date_premiere_echeance;
                  }
                } else {
                  if (form.date_souscription) {
                    next.date_premiere_echeance = addMonthsFE(form.date_souscription, 1);
                    if (next.date_premiere_echeance && form.duree_mois) {
                      next.date_cible = addMonthsFE(next.date_premiere_echeance, Number(form.duree_mois) - 1);
                    }
                  }
                }
                setForm(next);
              }}>
                <option value="in_fine">Prêt in fine</option>
                <option value="amortissable">Prêt amortissable</option>
                <option value="differe">Prêt différé</option>
              </select>
            </div>
            <div>
              <label>Fréquence intérêts</label>
              <select
                value={form.type_remb === 'differe' ? 'in_fine' : form.freq_interets}
                disabled={form.type_remb === 'differe'}
                onChange={e => setForm({ ...form, freq_interets: e.target.value })}
              >
                {form.type_remb === 'differe' ? (
                  <option value="in_fine">In fine (unique)</option>
                ) : (
                  <>
                    <option value="mensuel">Mensuel</option>
                    <option value="trimestriel">Trimestriel</option>
                  </>
                )}
              </select>
            </div>
            <div>
              <label>Date souscription *</label>
              <input type="date" required value={form.date_souscription} onChange={e => {
                const souscription = e.target.value;
                setForm(prev => {
                  const next = { ...prev, date_souscription: souscription };
                  if (!souscription || souscription.length !== 10) return next;
                  if (prev.type_remb === 'differe') {
                    if (prev.duree_mois) {
                      const tempDpe = addMonthsFE(souscription, 1);
                      const cible = addMonthsFE(tempDpe, Number(prev.duree_mois) - 1);
                      next.date_premiere_echeance = cible;
                      next.date_cible = cible;
                    }
                  } else {
                    next.date_premiere_echeance = addMonthsFE(souscription, 1);
                    if (next.date_premiere_echeance && prev.duree_mois) {
                      next.date_cible = addMonthsFE(next.date_premiere_echeance, Number(prev.duree_mois) - 1);
                    }
                  }
                  return next;
                });
                if (souscription && souscription.length === 10) {
                  lastValidSouscriptionRef.current = souscription;
                }
              }} />
            </div>
            <div>
              <label>{form.type_remb === 'differe' ? "Date d'échéance (versement unique) *" : 'Date 1ère échéance *'}</label>
              <input type="date" required value={form.date_premiere_echeance}
                onChange={e => {
                  const dpe = e.target.value;
                  const next = { ...form, date_premiere_echeance: dpe };
                  // Si le jour passe à ≤ 27 on désactive fin-de-mois
                  if (dayOfMonth(dpe) <= 27) next.echeance_fin_de_mois = false;
                  if (form.type_remb === 'differe') {
                    next.date_cible = dpe;
                  } else if (dpe && form.duree_mois) {
                    next.date_cible = next.echeance_fin_de_mois
                      ? addMonthsFinDeMoisFE(dpe, Number(form.duree_mois) - 1)
                      : addMonthsFE(dpe, Number(form.duree_mois) - 1);
                  }
                  setForm(next);
                }}
              />
              {/* ── Case "Dernier jour du mois" — visible si jour > 27 ── */}
              {(form.type_remb === 'in_fine' || form.type_remb === 'differe') &&
               dayOfMonth(form.date_premiere_echeance) > 27 && (
                <label style={{
                  display: 'inline-flex', alignItems: 'center', gap: 8,
                  marginTop: 6, cursor: 'pointer', userSelect: 'none',
                  fontSize: 'var(--fs-sm)', color: 'var(--text)',
                  width: 'fit-content',
                }}>
                  <input
                    type="checkbox"
                    style={{ width: 'auto', flexShrink: 0 }}
                    checked={form.echeance_fin_de_mois}
                    onChange={e => {
                      const checked = e.target.checked;
                      setForm(prev => {
                        const next = { ...prev, echeance_fin_de_mois: checked };
                        if (checked && prev.date_premiere_echeance) {
                          const newDpe = lastDayOfMonthFE(prev.date_premiere_echeance);
                          next.date_premiere_echeance = newDpe;
                          if (prev.type_remb === 'differe') {
                            next.date_cible = newDpe;
                          } else if (newDpe && prev.duree_mois) {
                            next.date_cible = addMonthsFinDeMoisFE(newDpe, Number(prev.duree_mois) - 1);
                          }
                        }
                        return next;
                      });
                    }}
                  />
                  Dernier jour du mois
                </label>
              )}
            </div>
            <div>
              <label>Date cible contractuelle{form.type_remb === 'differe' ? ' — calculée' : ''}</label>
              <input type="date" value={form.date_cible}
                readOnly={form.type_remb === 'differe'}
                onChange={e => setForm({ ...form, date_cible: e.target.value })}
              />
            </div>
            <div>
              <label>Pays d'exposition</label>
              <CountrySelect
                value={form.pays_exposition || 'FR'}
                onChange={code => setForm(f => ({ ...f, pays_exposition: code }))}
              />
            </div>
            <div>
              <label>Émetteur</label>
              <input value={form.emetteur}
                onChange={e => setForm({ ...form, emetteur: e.target.value })}
                placeholder="Nom de l'emprunteur"
              />
            </div>
            {editingId && (
              <div>
                <label>Statut</label>
                <select value={form.statut} onChange={e => setForm({ ...form, statut: e.target.value })}>
                  <option value="en_cours">En cours</option>
                  <option value="rembourse">Remboursé</option>
                  <option value="en_retard">En retard</option>
                  <option value="procedure">Procédure</option>
                  <option value="cloture">Clôturé</option>
                </select>
              </div>
            )}
            <div>
              <label>Référence</label>
              <input value={form.reference}
                onChange={e => setForm({ ...form, reference: e.target.value })}
                placeholder="N° de dossier, code projet…"
              />
            </div>
            <div style={{ gridColumn: 'span 2' }}>
              <label>Notes</label>
              <textarea rows={3} value={form.notes}
                onChange={e => setForm({ ...form, notes: e.target.value })}
                placeholder="Informations complémentaires…"
              />
            </div>

            {/* Catégories d'investissement */}
            <div style={{ gridColumn: 'span 3' }}>
              <label>Catégories d'investissement</label>
              <InvSelect
                items={categoriesInv}
                selected={form.categories_inv_ids || []}
                onChange={ids => setForm(f => ({ ...f, categories_inv_ids: ids }))}
                addApiPath="/categories-inv"
                onItemAdded={cat => setCategoriesInv(prev => [...prev, cat].sort((a,b) => a.nom.localeCompare(b.nom)))}
                emptyLabel="Aucune catégorie d'investissement"
                addLabel="Ajouter une catégorie d'investissement"
                inputPlaceholder="Nom de la catégorie…"
              />
            </div>

            {/* Secteurs d'investissement */}
            <div style={{ gridColumn: 'span 3' }}>
              <label>Secteurs d'investissement</label>
              <InvSelect
                items={secteursInv}
                selected={form.secteurs_inv_ids || []}
                onChange={ids => setForm(f => ({ ...f, secteurs_inv_ids: ids }))}
                addApiPath="/secteurs-inv"
                onItemAdded={sect => setSecteursInv(prev => [...prev, sect].sort((a,b) => a.nom.localeCompare(b.nom)))}
                emptyLabel="Aucun secteur d'investissement"
                addLabel="Ajouter un secteur d'investissement"
                inputPlaceholder="Nom du secteur…"
              />
            </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,
          }}>
            <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 = 'none'}
              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={() => { setOpenMenu(null); onDelete(openMenu.row); }}>
              <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 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg>
                            Supprimer
            </button>
          </div>
        </>
      )}

      <ConfirmModal
        open={!!deleteConfirm}
        message={deleteConfirm?.message}
        onConfirm={deleteConfirm?.onConfirm}
        onCancel={() => setDeleteConfirm(null)}
      />
    </>
  );
}
