import { useState, useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../../api.js';
import InvSelect from '../../components/InvSelect.jsx';
import Modal from '../../components/Modal.jsx';
import ConfirmModal from '../../components/ConfirmModal.jsx';
import CountrySelect, { COUNTRIES, FlagIcon } from '../../components/CountrySelect.jsx';
import ResultBanner from '../../components/ResultBanner.jsx';
import { useInvestisseur } from '../../context/InvestisseurContext.jsx';
import { memberLabel, fmtDate } from '../../utils/format.js';

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);
}

const countryLabel = code => COUNTRIES.find(c => c.code === code)?.name ?? code ?? '—';
const FISCALITE_LABELS = {
  flat_tax:              'Flat Tax',
  sans_fiscalite_locale: 'Sans fiscalité locale',
  avec_fiscalite_locale: 'Avec fiscalité locale',
};

const METHODE_REMB_LABELS = {
  portefeuille:       'Porte-monnaie de la plateforme',
  compte_courant:     "Compte courant de l'investisseur",
  choix_investisseur: "Au choix de l'investisseur (sur la plateforme)",
};

/** Reconstruit un objet investisseur minimal depuis les colonnes dénormalisées de la plateforme */
function platInvestisseur(p) {
  if (!p.investisseur_id) return null;
  return { id: p.investisseur_id, nom: p.investisseur_nom, prenom: p.investisseur_prenom, type: p.investisseur_type, type_fiscal: p.investisseur_type_fiscal };
}

function fmtFiscalite(p) {
  if (!p.fiscalite) return '—';
  const base = FISCALITE_LABELS[p.fiscalite] ?? p.fiscalite;
  if (p.fiscalite === 'avec_fiscalite_locale' && p.taux_fiscalite_locale != null) {
    return `${base} (${p.taux_fiscalite_locale} %)`;
  }
  return base;
}

const EMPTY_PLAT = { nom: '', url: '', domiciliation: 'france', fiscalite: 'flat_tax', taux_fiscalite_locale: '', type_produit_fiscal: '2TT', methode_remboursement: 'portefeuille', investisseur_id: null, date_ouverture: '', logo_filename: null, type_pret_defaut: '', freq_interets_defaut: '', referentiel_id: null };

const LOGO_BASE = (import.meta.env.VITE_API_URL || '/api').replace(/\/api$/, '') + '/api/logos/';
const logoUrl = (filename) => filename ? LOGO_BASE + filename : null;

function applyDomiciliationChange(state, newDomicil) {
  const next = { ...state, domiciliation: newDomicil };
  if (newDomicil === 'FR') {
    next.fiscalite = 'flat_tax';
    next.taux_fiscalite_locale = '';
  } else if (state.fiscalite === 'flat_tax') {
    next.fiscalite = 'sans_fiscalite_locale';
    next.taux_fiscalite_locale = '';
  }
  return next;
}

function applyFiscaliteChange(state, newFiscalite) {
  const next = { ...state, fiscalite: newFiscalite };
  if (newFiscalite !== 'avec_fiscalite_locale') next.taux_fiscalite_locale = '';
  return next;
}

function platsToCSV(plats) {
  const BOM = '﻿';
  const sep = ';';
  const q   = v => `"${String(v ?? '').replace(/"/g, '""')}"`;
  const headers = ['ID', 'Nom', 'URL', 'Domiciliation', 'Fiscalité', 'Taux fiscal local (%)', 'Créé le'];
  const rows = plats.map(p => [
    p.id, p.nom, p.url || '',
    countryLabel(p.domiciliation),
    FISCALITE_LABELS[p.fiscalite] ?? p.fiscalite ?? '',
    p.taux_fiscalite_locale ?? '',
    p.created_at ? new Date(p.created_at).toLocaleDateString('fr-FR') : '',
  ]);
  return BOM + [headers, ...rows].map(r => r.map(q).join(sep)).join('\r\n');
}

function platsToXLS(plats) {
  const esc  = v => String(v ?? '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
  const cell = (v, t = 'String') => `<Cell><Data ss:Type="${t}">${esc(v)}</Data></Cell>`;
  const mkRow = cells => `    <Row>${cells.join('')}</Row>`;
  const header = mkRow(['ID','Nom','URL','Domiciliation','Fiscalité','Taux fiscal local (%)','Créé le'].map(h => cell(h)));
  const dataRows = plats.map(p => mkRow([
    cell(p.id, 'Number'), cell(p.nom), cell(p.url || ''),
    cell(countryLabel(p.domiciliation)),
    cell(FISCALITE_LABELS[p.fiscalite] ?? p.fiscalite ?? ''),
    cell(p.taux_fiscalite_locale ?? ''),
    cell(p.created_at ? new Date(p.created_at).toLocaleDateString('fr-FR') : ''),
  ])).join('\n');
  return `<?xml version="1.0" encoding="UTF-8"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
          xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
  <Styles><Style ss:ID="h"><Font ss:Bold="1"/></Style></Styles>
  <Worksheet ss:Name="Plateformes">
    <Table>
${header}
${dataRows}
    </Table>
  </Worksheet>
</Workbook>`;
}

/* ── Icônes utilitaires ──────────────────────────────────────── */
function IconExport() {
  return <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><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>;
}
function IconCSV() {
  return <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><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"/><line x1="10" y1="9" x2="14" y2="9"/></svg>;
}
function IconXLS() {
  return <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><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>;
}
function IconJSON() {
  return <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><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.5 1.5 0 0 1 0 3H8v-3z"/><path d="M14 13h2v1.5a1.5 1.5 0 0 1-3 0V13z"/></svg>;
}
function IconImport() {
  return <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 14 12 9 17 14"/><line x1="12" y1="9" x2="12" y2="21"/></svg>;
}

/* ── ExportDropdown ──────────────────────────────────────────── */
function ExportDropdown({ disabled, onCSV, onXLS, onJSON, title = 'Exporter' }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);

  useEffect(() => {
    if (!open) return;
    const handler = (e) => { if (!ref.current?.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [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={title}
        aria-haspopup="menu" aria-expanded={open}>
        <IconExport />
      </button>
      {open && (
        <div className="export-dropdown" role="menu">
          <button role="menuitem" onClick={() => choose(onCSV)}>
            <IconCSV /><span><strong>Format CSV</strong><small>Compatible Excel, LibreOffice</small></span>
          </button>
          <button role="menuitem" onClick={() => choose(onXLS)}>
            <IconXLS /><span><strong>Format Excel</strong><small>Fichier .xls natif Microsoft</small></span>
          </button>
          {onJSON && (
            <button role="menuitem" onClick={() => choose(onJSON)}>
              <IconJSON /><span><strong>Format JSON</strong><small>Données structurées</small></span>
            </button>
          )}
        </div>
      )}
    </div>
  );
}

/* ── Helpers PFU ─────────────────────────────────────────────── */




function PlatDetailPanel({ plat, onEdit }) {
  const navigate = useNavigate();
  const [platCatsInv,  setPlatCatsInv]  = useState([]);
  const [platSectsInv, setPlatSectsInv] = useState([]);
  useEffect(() => {
    if (!plat) { setPlatCatsInv([]); setPlatSectsInv([]); return; }
    Promise.all([
      api.get(`/plateformes/${plat.id}/categories-inv`).catch(() => []),
      api.get(`/plateformes/${plat.id}/secteurs-inv`).catch(() => []),
    ]).then(([cats, sects]) => { setPlatCatsInv(cats); setPlatSectsInv(sects); });
  }, [plat?.id]);

  if (!plat) return (
    <div className="dr-detail dr-detail-empty">
      <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.25, marginBottom: 8 }}>
        <rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/>
        <line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/>
      </svg>
      <span>Sélectionnez une plateforme</span>
    </div>
  );

  const inv = platInvestisseur(plat);
  const fields = [
    { label: 'Plateforme',    value: plat.nom },
    plat.url && {
      label: 'Site web',
      value: <a href={plat.url} target="_blank" rel="noreferrer"
        style={{ wordBreak: 'break-all', color: 'var(--primary)' }}>{plat.url}</a>,
    },
    { label: 'Détenteur',     value: inv ? memberLabel(inv) : '—' },
    plat.date_ouverture && { label: "Date d'ouverture", value: fmtDate(plat.date_ouverture) },
    { label: 'Domiciliation', value: plat.domiciliation ? <span style={{ display:'inline-flex', alignItems:'center', gap:5 }}><FlagIcon code={plat.domiciliation} size={16} />{countryLabel(plat.domiciliation)}</span> : '—' },
    { label: 'Fiscalité',     value: fmtFiscalite(plat) },
    plat.domiciliation === 'FR' && {
      label: 'Déclaration 2561',
      value: (plat.type_produit_fiscal ?? '2TT') === '2TR'
        ? 'Case 2TR — Produits de placement à revenu fixe'
        : 'Case 2TT — Produits des minibons et prêts participatifs',
    },
    { label: 'Méthode de remboursement', value: METHODE_REMB_LABELS[plat.methode_remboursement] ?? '—' },
    platCatsInv.length > 0 && {
      label: "Catégories d'investissement",
      value: <div style={{ display:'flex', flexWrap:'wrap', gap:4 }}>{platCatsInv.map(c => <span key={c.id} className="chip-cat">{c.nom}</span>)}</div>,
    },
    platSectsInv.length > 0 && {
      label: "Secteurs d'investissement",
      value: <div style={{ display:'flex', flexWrap:'wrap', gap:4 }}>{platSectsInv.map(s => <span key={s.id} className="chip-sect">{s.nom}</span>)}</div>,
    },
    plat.type_pret_defaut && { label: 'Type de prêt (défaut)', value: { in_fine: 'In fine', amortissable: 'Amortissable', differe: 'Différé' }[plat.type_pret_defaut] ?? plat.type_pret_defaut },
    plat.freq_interets_defaut && { label: 'Périodicité (défaut)', value: { mensuel: 'Mensuelle', trimestriel: 'Trimestrielle', in_fine: 'In fine' }[plat.freq_interets_defaut] ?? plat.freq_interets_defaut },
    {
      label: 'Investissements',
      value: plat.nb_investissements != null
        ? `${plat.nb_investissements} investissement${plat.nb_investissements !== 1 ? 's' : ''}`
        : '—',
    },
    plat.notes && { label: 'Notes', value: plat.notes },
  ].filter(Boolean);

  const logo = logoUrl(plat.logo_filename);

  return (
    <div className="dr-detail">
      {logo && (
        <div style={{ display: 'flex', justifyContent: 'center', padding: '12px 0 4px' }}>
          <img src={logo} alt={`Logo ${plat.nom}`} className="logo-plateforme"
            style={{ maxHeight: 56, maxWidth: 160, objectFit: 'contain' }}
            onError={e => { e.currentTarget.style.display = 'none'; }}
          />
        </div>
      )}
      <div className="dr-detail-title">Détail de la plateforme</div>
      <div className="dr-detail-fields">
        {fields.map(f => (
          <div className="dr-detail-field" key={f.label}>
            <span className="dr-detail-label">{f.label}</span>
            <span className="dr-detail-value">{f.value}</span>
          </div>
        ))}
      </div>
      <div className="dr-detail-footer">
        {plat.referentiel_id && (
          <button
            className="ghost"
            onClick={() => navigate(`/referentiel/${plat.referentiel_id}`)}
            style={{ marginBottom: 8, width: '100%', fontSize: 13 }}
          >
            Voir le profil de la plateforme
          </button>
        )}
        <button className="dr-detail-edit-btn" onClick={() => onEdit(plat)}>
          Modifier la plateforme
        </button>
      </div>
    </div>
  );
}

/* ── Panneau de détail PFU ───────────────────────────────────── */


export default function PlateformesSection() {
  // ── State ──────────────────────────────────────────────────────
  const [plats, setPlats]           = useState([]);
  const [investisseurs, setInvestisseurs] = useState([]);
  const [referentiel, setReferentiel] = useState([]);
  const [newPlat, setNewPlat]       = useState(EMPTY_PLAT);
  const [newPlatLogoFile, setNewPlatLogoFile]   = useState(null);
  const [newPlatLogoPreview, setNewPlatLogoPreview] = useState(null);
  const [editPlat, setEditPlat]     = useState(null);
  const [editPlatLogoFile, setEditPlatLogoFile]   = useState(null);
  const [editPlatLogoPreview, setEditPlatLogoPreview] = useState(null);
  const [selectedPlat, setSelectedPlat] = useState(null);
  const [showNewPlat, setShowNewPlat]   = useState(false);
  const [platOpenMenu,   setPlatOpenMenu]   = useState(null);  // { plat, x, y }
  const [platExporting,  setPlatExporting]  = useState(false);
  const [platImportResult, setPlatImportResult] = useState(null);
  // Catégories d'investissement (globales + privées)
  const [categoriesInv, setCategoriesInv]   = useState([]);
  const [selectedCatInv, setSelectedCatInv] = useState(null);
  const [editingCatInv,  setEditingCatInv]  = useState(null);  // id en cours d'édition
  const [editingNomCatInv, setEditingNomCatInv] = useState('');
  const [newCatInvNom,   setNewCatInvNom]   = useState('');
  const [showNewCatInv,  setShowNewCatInv]  = useState(false);

  // Secteurs d'investissement (globaux + privés)
  const [secteursInv, setSecteursInv]       = useState([]);
  const [selectedSectInv, setSelectedSectInv] = useState(null);
  const [editingSectInv,  setEditingSectInv]  = useState(null);
  const [editingNomSectInv, setEditingNomSectInv] = useState('');
  const [newSectInvNom,   setNewSectInvNom]   = useState('');
  const [showNewSectInv,  setShowNewSectInv]  = useState(false);

  // PFU
  const [showPfoDetail, setShowPfoDetail] = useState(false);


  const [err, setErr] = useState(null);
  const [msg, setMsg] = useState(null);
  const [confirmDelete, setConfirmDelete] = useState(null);
  const platImportRef = useRef(null);

  const load = async () => {
    const [p, invs, ref, catInv, sectInv] = await Promise.all([
      api.get('/plateformes'),
      api.get('/investisseurs'),
      api.get('/plateformes/referentiel-list'),
      api.get('/categories-inv'),
      api.get('/secteurs-inv'),
    ]);
    setPlats(p);
    setInvestisseurs(invs);
    setReferentiel(ref);
    setCategoriesInv(catInv);
    setSecteursInv(sectInv);
    setSelectedPlat(prev => prev ? (p.find(x => x.id === prev.id) ?? null) : null);
  };

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

  useEffect(() => {
    if (plats.length === 0) return;
    setSelectedPlat(prev => prev ? prev : plats[0]);
  }, [plats]); // eslint-disable-line

  const handleLogoFile = (file, setFile, setPreview) => {
    if (!file) { setFile(null); setPreview(null); return; }
    setFile(file);
    const reader = new FileReader();
    reader.onload = (ev) => setPreview(ev.target.result);
    reader.readAsDataURL(file);
  };

  /* ── Catégories d'investissement (privées) ──────────────────────── */
  const saveCatInv = async (nom) => {
    if (!nom.trim()) return;
    try {
      const row = await api.post('/categories-inv', { nom: nom.trim() });
      setCategoriesInv(prev => [...prev, row].sort((a, b) =>
        b.is_global - a.is_global || a.nom.localeCompare(b.nom)));
      setShowNewCatInv(false); setNewCatInvNom(''); setErr(null);
    } catch (e) { setErr(e.message || 'Erreur'); }
  };
  const renameCatInv = async (id, nom) => {
    if (!nom.trim()) return;
    try {
      await api.put(`/categories-inv/${id}`, { nom: nom.trim() });
      setCategoriesInv(prev => prev.map(c => c.id === id ? { ...c, nom: nom.trim() } : c));
      setEditingCatInv(null);
    } catch (e) { setErr(e.message || 'Erreur'); }
  };
  const delCatInv = async (id) => {
    try {
      await api.del(`/categories-inv/${id}`);
      setCategoriesInv(prev => prev.filter(c => c.id !== id));
      if (selectedCatInv?.id === id) setSelectedCatInv(null);
    } catch (e) { setErr(e.message || 'Erreur'); }
  };

  /* ── Secteurs d'investissement (privés) ──────────────────────── */
  const saveSectInv = async (nom) => {
    if (!nom.trim()) return;
    try {
      const row = await api.post('/secteurs-inv', { nom: nom.trim() });
      setSecteursInv(prev => [...prev, row].sort((a, b) =>
        b.is_global - a.is_global || a.nom.localeCompare(b.nom)));
      setShowNewSectInv(false); setNewSectInvNom(''); setErr(null);
    } catch (e) { setErr(e.message || 'Erreur'); }
  };
  const renameSectInv = async (id, nom) => {
    if (!nom.trim()) return;
    try {
      await api.put(`/secteurs-inv/${id}`, { nom: nom.trim() });
      setSecteursInv(prev => prev.map(s => s.id === id ? { ...s, nom: nom.trim() } : s));
      setEditingSectInv(null);
    } catch (e) { setErr(e.message || 'Erreur'); }
  };
  const delSectInv = async (id) => {
    try {
      await api.del(`/secteurs-inv/${id}`);
      setSecteursInv(prev => prev.filter(s => s.id !== id));
      if (selectedSectInv?.id === id) setSelectedSectInv(null);
    } catch (e) { setErr(e.message || 'Erreur'); }
  };

  /** Upload le logo vers le serveur après que la plateforme a été créée/sauvée */
  const uploadLogo = async (platId, file) => {
    if (!file) return null;
    const fd = new FormData();
    fd.append('logo', file);
    return api.upload(`/plateformes/${platId}/logo`, fd);
  };

  /* ── Plateformes ─────────────────────────────────────────────── */
  const addPlat = async (e) => {
    e.preventDefault(); setErr(null); setMsg(null);
    try {
      const created = await api.post('/plateformes', {
        ...newPlat,
        taux_fiscalite_locale: newPlat.fiscalite === 'avec_fiscalite_locale' && newPlat.taux_fiscalite_locale !== ''
          ? Number(newPlat.taux_fiscalite_locale) : null,
        methode_remboursement: newPlat.methode_remboursement || 'portefeuille',
        investisseur_id: newPlat.investisseur_id ? Number(newPlat.investisseur_id) : null,
        date_ouverture: newPlat.date_ouverture || null,
        type_pret_defaut: newPlat.type_pret_defaut || null,
        freq_interets_defaut: newPlat.freq_interets_defaut || null,
        referentiel_id: newPlat.referentiel_id ? Number(newPlat.referentiel_id) : null,
      });
      if (newPlatLogoFile) await uploadLogo(created.id, newPlatLogoFile);
      setNewPlat(EMPTY_PLAT);
      setNewPlatLogoFile(null);
      setNewPlatLogoPreview(null);
      setShowNewPlat(false);
      await load();
    } catch (e) { setErr(e.message); }
  };

  const delPlat = (id) => {
    setConfirmDelete({
      message: 'Supprimer cette plateforme ?',
      onConfirm: async () => {
        try {
          await api.del(`/plateformes/${id}`);
          setSelectedPlat(null);
          await load();
        } catch (e) { setErr(e.message); }
        finally { setConfirmDelete(null); }
      },
    });
  };

  // ── Export/Import ZIP plateformes ─────────────────────────────────────
  const handlePlatExportAll = async () => {
    try {
      setPlatExporting(true);
      const blob = await api.blob('/plateformes/export');
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `plateformes-${new Date().toISOString().slice(0, 10)}.zip`;
      document.body.appendChild(a); a.click(); document.body.removeChild(a);
      URL.revokeObjectURL(url);
    } catch (e) { setPlatImportResult({ ok: false, msg: e.message }); }
    finally { setPlatExporting(false); }
  };

  const handlePlatExportOne = async (plat) => {
    try {
      const blob = await api.blob(`/plateformes/${plat.id}/export`);
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `${plat.nom.toLowerCase().replace(/[^a-z0-9]+/g, '-')}-${new Date().toISOString().slice(0, 10)}.zip`;
      document.body.appendChild(a); a.click(); document.body.removeChild(a);
      URL.revokeObjectURL(url);
    } catch (e) { setPlatImportResult({ ok: false, msg: e.message }); }
  };

  const handlePlatImportZip = async (file) => {
    try {
      const fd = new FormData();
      fd.append('file', file);
      const r = await api.upload('/plateformes/import-zip', fd);
      setPlatImportResult({ ok: true, msg: `Import terminé : ${r.created} créée(s), ${r.updated} mise(s) à jour sur ${r.total} entrée(s).` });
      load();
    } catch (e) { setPlatImportResult({ ok: false, msg: e.message }); }
  };

  const openEditPlat = async (p) => {
    setEditPlatLogoFile(null);
    setEditPlatLogoPreview(null);
    // Charger les associations catégories/secteurs d'investissement de la plateforme
    const [platCatsInv, platSectsInv] = await Promise.all([
      api.get(`/plateformes/${p.id}/categories-inv`).catch(() => []),
      api.get(`/plateformes/${p.id}/secteurs-inv`).catch(() => []),
    ]);
    setEditPlat({
      id: p.id, nom: p.nom, url: p.url || '',
      categories_inv_ids:   platCatsInv.map(c => c.id),
      secteurs_inv_ids:     platSectsInv.map(s => s.id),
      inherited_cat_ids:    platCatsInv.filter(c => c.is_inherited).map(c => c.id),
      inherited_sect_ids:   platSectsInv.filter(s => s.is_inherited).map(s => s.id),
      domiciliation: p.domiciliation || 'france',
      fiscalite: p.fiscalite || 'flat_tax',
      taux_fiscalite_locale: p.taux_fiscalite_locale ?? '',
      type_produit_fiscal: p.type_produit_fiscal || '2TT',
      methode_remboursement: p.methode_remboursement || 'portefeuille',
      investisseur_id: p.investisseur_id ?? null,
      date_ouverture: p.date_ouverture || '',
      logo_filename: p.logo_filename || null,
      type_pret_defaut: p.type_pret_defaut || '',
      freq_interets_defaut: p.freq_interets_defaut || '',
      referentiel_id: p.referentiel_id ?? null,
      referentiel_nom: p.referentiel_nom ?? null,
      overridden_fields: p.overridden_fields ?? [],
    });
  };

  const saveEditPlat = async (e) => {
    e.preventDefault(); setErr(null); setMsg(null);
    try {
      await api.put(`/plateformes/${editPlat.id}`, {
        nom: editPlat.nom, url: editPlat.url || '',
        domiciliation: editPlat.domiciliation,
        fiscalite: editPlat.fiscalite,
        taux_fiscalite_locale: editPlat.fiscalite === 'avec_fiscalite_locale' && editPlat.taux_fiscalite_locale !== ''
          ? Number(editPlat.taux_fiscalite_locale) : null,
        type_produit_fiscal: editPlat.type_produit_fiscal || '2TT',
        methode_remboursement: editPlat.methode_remboursement || 'portefeuille',
        investisseur_id: editPlat.investisseur_id ? Number(editPlat.investisseur_id) : null,
        date_ouverture: editPlat.date_ouverture || null,
        type_pret_defaut: editPlat.type_pret_defaut || null,
        freq_interets_defaut: editPlat.freq_interets_defaut || null,
      });
      if (editPlatLogoFile) await uploadLogo(editPlat.id, editPlatLogoFile);
      // Sauvegarder les associations catégories/secteurs d'investissement
      await Promise.all([
        api.put(`/plateformes/${editPlat.id}/categories-inv`, { ids: editPlat.categories_inv_ids || [] }),
        api.put(`/plateformes/${editPlat.id}/secteurs-inv`,   { ids: editPlat.secteurs_inv_ids   || [] }),
      ]);
      setMsg('Plateforme mise à jour.');
      setTimeout(() => setMsg(null), 3000);
      setEditPlatLogoFile(null);
      setEditPlatLogoPreview(null);
      setEditPlat(null);
      await load();
    } catch (e) { setErr(e.message); }
  };

  const delLogoPlat = async (id) => {
    try {
      await api.del(`/plateformes/${id}/logo`);
      setEditPlat(ep => ep ? { ...ep, logo_filename: null } : ep);
      await load();
    } catch (e) { setErr(e.message); }
  };

  /* ── PFU CRUD ────────────────────────────────────────────────── */



  return (
    <>
      {err && <div className="error" style={{ marginBottom: 12 }}>{err}</div>}
      {msg && <div className="success-msg" style={{ marginBottom: 12 }}>{msg}</div>}
<div className="dr-mouvements-layout">

  {/* Colonne gauche — liste */}
  <div className="dr-mouvements-list">
    <div className="card" style={{ display: 'flex', flexDirection: 'column' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
        <div>
          <h3 style={{ margin: 0 }}>Mes plateformes</h3>
          <p className="text-muted" style={{ margin: '4px 0 0', fontSize: 'var(--fs-sm)' }}>
            Plateformes de crowdlending que vous utilisez.
          </p>
        </div>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
          <ExportDropdown
            disabled={plats.length === 0}
            onCSV={() => dlBlob(platsToCSV(plats), 'plateformes.csv', 'text/csv;charset=utf-8')}
            onXLS={() => dlBlob(platsToXLS(plats), 'plateformes.xls', 'application/vnd.ms-excel')}
          />
          <button onClick={handlePlatExportAll} disabled={platExporting || plats.length === 0}
            title="Exporter toutes les plateformes en ZIP"
            style={{ padding: '7px 12px', borderRadius: 6, border: '1px solid var(--border)', fontSize: 13, fontWeight: 600, cursor: 'pointer', background: 'var(--surface-2)', color: 'var(--text-muted)', display: 'flex', alignItems: 'center', gap: 5 }}>
            <svg width="13" height="13" 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>
            {platExporting ? '…' : 'Export ZIP'}
          </button>
          <button onClick={() => platImportRef.current?.click()}
            title="Importer un fichier ZIP de plateformes"
            style={{ padding: '7px 12px', borderRadius: 6, border: '1px solid var(--border)', fontSize: 13, fontWeight: 600, cursor: 'pointer', background: 'var(--surface-2)', color: 'var(--text-muted)', display: 'flex', alignItems: 'center', gap: 5 }}>
            <svg width="13" height="13" 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="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
            Import ZIP
          </button>
          <input ref={platImportRef} type="file" accept=".zip" style={{ display: 'none' }}
            onChange={e => { const f = e.target.files[0]; e.target.value = ''; if (f) handlePlatImportZip(f); }} />
          <button className="primary" type="button"
            onClick={() => { setNewPlat(EMPTY_PLAT); setErr(null); setShowNewPlat(true); }}>
            + Ajouter
          </button>
        </div>
      </div>

      {platImportResult && <ResultBanner result={platImportResult} onDismiss={() => setPlatImportResult(null)} style={{ marginBottom: 12 }} />}

      <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
          <thead>
            <tr style={{ borderBottom: '1px solid var(--border)', background: 'var(--surface-2)' }}>
              <th style={{ padding: '10px 8px', width: 40 }}></th>
              <th style={{ padding: '10px 16px', textAlign: 'left' }}>Nom</th>
              <th style={{ padding: '10px 8px', textAlign: 'left' }}>Domiciliation</th>
              <th style={{ padding: '10px 8px', textAlign: 'left' }}>Catégories</th>
              <th style={{ padding: '10px 8px', textAlign: 'left' }}>Secteurs</th>
              <th style={{ padding: '10px 8px', textAlign: 'left' }}>Détenteur</th>
              <th style={{ padding: '10px 16px', textAlign: 'center', width: 60 }}>Invest.</th>
              <th style={{ padding: '10px 8px', width: 40 }}></th>
            </tr>
          </thead>
          <tbody>
            {plats.length === 0 && (
              <tr><td colSpan={7} className="text-muted" style={{ textAlign: 'center', padding: 24 }}>Aucune plateforme</td></tr>
            )}
            {plats.map((p, i) => {
              const imgSrc = p.icone_filename ? logoUrl(p.icone_filename) : p.logo_filename ? logoUrl(p.logo_filename) : null;
              const inv = platInvestisseur(p);
              const cats = p.categories_inv || [];
              const sects = p.secteurs_inv || [];
              return (
                <tr key={p.id}
                  onClick={() => setSelectedPlat(selectedPlat?.id === p.id ? null : p)}
                  style={{
                    borderBottom: i < plats.length - 1 ? '1px solid var(--border)' : 'none',
                    cursor: 'pointer',
                    background: selectedPlat?.id === p.id ? 'var(--surface-2)' : 'none',
                  }}
                  onMouseEnter={e => { if (selectedPlat?.id !== p.id) e.currentTarget.style.background = 'var(--surface-2)'; }}
                  onMouseLeave={e => { if (selectedPlat?.id !== p.id) e.currentTarget.style.background = 'none'; }}>
                  <td style={{ padding: '8px 8px 8px 16px', width: 40 }}>
                    {imgSrc
                      ? <img src={imgSrc} alt="" style={{ width: 32, height: 32, objectFit: 'contain', borderRadius: 4, display: 'block' }} />
                      : <div style={{ width: 32, height: 32, borderRadius: 4, background: 'var(--surface-2)', border: '1px dashed var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--text-muted)', fontSize: 16 }}>×</div>
                    }
                  </td>
                  <td style={{ padding: '10px 16px' }}>
                    <div style={{ fontWeight: 600 }}>{p.nom}</div>
                  </td>
                  <td style={{ padding: '10px 8px', color: 'var(--text-muted)', fontSize: 12 }}>
                    {p.domiciliation
                      ? <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
                          <FlagIcon code={p.domiciliation} size={15} />{countryLabel(p.domiciliation)}
                        </span>
                      : '—'}
                  </td>
                  <td style={{ padding: '10px 8px' }}>
                    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
                      {cats.slice(0, 2).map(c => <span key={c.id} className="chip-cat" style={{ fontSize: 11 }}>{c.nom}</span>)}
                      {cats.length > 2 && <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>+{cats.length - 2}</span>}
                      {cats.length === 0 && <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>—</span>}
                    </div>
                  </td>
                  <td style={{ padding: '10px 8px' }}>
                    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
                      {sects.slice(0, 2).map(s => <span key={s.id} className="chip-sect" style={{ fontSize: 11 }}>{s.nom}</span>)}
                      {sects.length > 2 && <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>+{sects.length - 2}</span>}
                      {sects.length === 0 && <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>—</span>}
                    </div>
                  </td>
                  <td style={{ padding: '10px 8px', fontSize: 12, color: 'var(--text-muted)' }}>
                    {inv ? memberLabel(inv) : '—'}
                  </td>
                  <td style={{ padding: '10px 16px', textAlign: 'center', fontWeight: 600,
                    color: (p.nb_investissements ?? 0) > 0 ? 'var(--text)' : 'var(--text-muted)' }}>
                    {p.nb_investissements ?? 0}
                  </td>
                  <td style={{ padding: '10px 8px', textAlign: 'right' }}>
                    <button
                      style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '4px 8px', borderRadius: 4, fontSize: 18, color: 'var(--text-muted)', lineHeight: 1 }}
                      onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
                      onMouseLeave={e => e.currentTarget.style.background = 'none'}
                      onClick={e => { e.stopPropagation(); const rect = e.currentTarget.getBoundingClientRect(); setPlatOpenMenu({ plat: p, x: rect.right, y: rect.bottom }); }}
                    >⋮</button>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </div>
  </div>

  {/* Colonne droite — détail */}
  <div className="dr-mouvements-detail">
    <PlatDetailPanel
      plat={selectedPlat}
      onEdit={openEditPlat}
    />
  </div>
</div>

{/* Menu ⋮ plateformes */}
{platOpenMenu && (
  <>
    <div style={{ position: 'fixed', inset: 0, zIndex: 299 }} onClick={() => setPlatOpenMenu(null)} />
    <div style={{ position: 'fixed', left: platOpenMenu.x, top: platOpenMenu.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: 170 }}>
      {[
        { icon: <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>, label: 'Modifier',
          onClick: () => { const p = platOpenMenu.plat; setPlatOpenMenu(null); openEditPlat(p); } },
        { icon: <svg width="13" height="13" 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>, label: 'Exporter',
          onClick: () => { const p = platOpenMenu.plat; setPlatOpenMenu(null); handlePlatExportOne(p); } },
        { icon: <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>, label: 'Supprimer',
          onClick: () => { const p = platOpenMenu.plat; setPlatOpenMenu(null); delPlat(p.id); }, color: 'var(--danger)' },
      ].map(({ icon, label, onClick, color }) => (
        <button key={label}
          style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '8px 14px',
            background: 'none', border: 'none', cursor: 'pointer',
            fontSize: 'var(--fs-sm)', color: color || 'var(--text)', textAlign: 'left' }}
          onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
          onMouseLeave={e => e.currentTarget.style.background = 'none'}
          onClick={onClick}>
          <span style={{ opacity: 0.7, flexShrink: 0, display: 'flex' }}>{icon}</span>
          {label}
        </button>
      ))}
    </div>
  </>
)}
      <ConfirmModal
        open={!!confirmDelete}
        title="Supprimer la plateforme"
        message={confirmDelete?.message}
        onConfirm={confirmDelete?.onConfirm}
        onCancel={() => setConfirmDelete(null)}
      />
    </>
  );
}
