import React, { useState, useRef, useEffect, useCallback, useMemo } from "react";
import QRCode from "react-qr-code";

// ── TYPES ─────────────────────────────────────────────
interface TvaItem {
    taux: string;            // "0", "5.5", "10", "20", ou "MIXED" pour ligne multi-TVA
    montantTTC: string;
    // ✅ Répartition TVA quand la ligne a plusieurs taux remplis
    tvaBreakdown?: {
        tva21?: string;
        tva55?: string;
        tva10?: string;
        tva20?: string;
    };
}
interface Participant { nom: string; prenom: string; societe?: string; }
interface Depense {
    id: number; categorie: string; date: string; libelle: string;
    description: string; km: string; chevaux: number;
    tvaItems: TvaItem[]; nombreParticipants: string;
    participants: Participant[]; files: File[];
    qrLink?: string | null;
    qrUploaded?: boolean;
    qrNoteRef?: string;
    filesMeta?: FileMeta[];
    qrFiles?: QrFileMeta[];
    nuits: string;
}
interface BrouillonServeur {
    id: number; libelle: string; lignesJson: string;
    DateModification: string; description?: string; date?: string;
}
interface FileMeta { name: string; type: string; size: number; preview?: string; }
interface QrFileMeta {
    fileName: string;
    uploadUrl: string;
    origin?: 'qr' | 'upload' | 'sharepoint';
}
interface TvaItemBackend {
    taux: string;
    montantTTC: string;
    montantHT: string;
    tvaBreakdown?: {
        tva21?: string;
        tva55?: string;
        tva10?: string;
        tva20?: string;
    };
}
interface NouvelleNoteProps {
    onSubmit: (
        titre: string, dateDebut: string, dateFin: string,
        commentaire: string, depenses: any[]
    ) => Promise<void>;
    onCancel?: () => void;
    apiBaseUrl: string;
    authToken: string;
    initialBrouillonId?: number | null;
    libelleInitial?: string;
    dateDebutInitiale?: string;
    commentaireInitial?: string;
    depensesInitiales?: any[];
    onNavigateToProfil?: () => void;
}

// ── CONSTANTES ────────────────────────────────────────
const BAREME_KM = [
    { cv: 3, label: "3 CV et moins", t1: 0.529, t2_a: 0.316, t2_b: 1061, t3: 0.369 },
    { cv: 4, label: "4 CV", t1: 0.606, t2_a: 0.340, t2_b: 1330, t3: 0.408 },
    { cv: 5, label: "5 CV", t1: 0.636, t2_a: 0.356, t2_b: 1391, t3: 0.427 },
    { cv: 6, label: "6 CV", t1: 0.665, t2_a: 0.374, t2_b: 1457, t3: 0.448 },
    { cv: 7, label: "7 CV et plus", t1: 0.697, t2_a: 0.394, t2_b: 1512, t3: 0.470 },
];
const CATEGORIES_DEFAULT = ["Deplacement kilometrique", "Repas", "Hebergement", "Transport", "Autre"];
const TAUX_TVA = [
    { taux: 0, libelle: "0% — Exonéré" },
    { taux: 5.5, libelle: "5,5% — Réduit" },
    { taux: 10, libelle: "10% — Intermédiaire" },
    { taux: 20, libelle: "20% — Normal" },
];

// ── Colonnes TVA Excel — toutes saisies manuellement ──
// Structure : TTC | TVA 2,1% | TVA 5,5% | TVA 10% | TVA 20% | HT
const TVA_EXCEL_COLS = [
    { taux: "2.1", label: "TVA 2,1%" },
    { taux: "5.5", label: "TVA 5,5%" },
    { taux: "10", label: "TVA 10%" },
    { taux: "20", label: "TVA 20,0%" },
];

// Catégories utilisant le tableau Excel TVA
const CATS_EXCEL_TVA = ["repas", "hebergement", "transport"];

const CAT_ICONS: Record<string, string> = {
    "Deplacement kilometrique": "🚗",
    "Repas": "🍽️",
    "Hebergement": "🏨",
    "Transport": "🚆",
    "Autre": "📋",
};

// ── HELPERS ───────────────────────────────────────────
const fmt = (v: number) => new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR" }).format(v);

const ttcToHt = (ttc: number, taux: number): number =>
    parseFloat((ttc / (1 + taux / 100)).toFixed(2));

const ttcToTva = (ttc: number, taux: number): number => {
    const ht = ttcToHt(ttc, taux);
    return parseFloat((ttc - ht).toFixed(2));
};

// ✅ Helpers pour le cas MIXED
const sumTvaBreakdown = (bd?: TvaItem['tvaBreakdown']): number => {
    if (!bd) return 0;
    return (parseFloat(bd.tva21 || "0") || 0)
        + (parseFloat(bd.tva55 || "0") || 0)
        + (parseFloat(bd.tva10 || "0") || 0)
        + (parseFloat(bd.tva20 || "0") || 0);
};

const itemToHt = (item: TvaItem): number => {
    const ttc = parseFloat(item.montantTTC) || 0;
    if (ttc <= 0) return 0;
    if (item.taux === "MIXED" && item.tvaBreakdown) {
        return parseFloat((ttc - sumTvaBreakdown(item.tvaBreakdown)).toFixed(2));
    }
    const taux = parseFloat(item.taux) || 0;
    return ttcToHt(ttc, taux);
};

const itemToTva = (item: TvaItem): number => {
    const ttc = parseFloat(item.montantTTC) || 0;
    if (ttc <= 0) return 0;
    if (item.taux === "MIXED" && item.tvaBreakdown) {
        return parseFloat(sumTvaBreakdown(item.tvaBreakdown).toFixed(2));
    }
    const taux = parseFloat(item.taux) || 0;
    return ttcToTva(ttc, taux);
};

const tvaItemToBackend = (item: TvaItem): TvaItemBackend => {
    const ttc = parseFloat(item.montantTTC) || 0;

    // ✅ Cas MIXED : HT = TTC - somme TVA du breakdown
    if (item.taux === "MIXED" && item.tvaBreakdown) {
        const totTva = sumTvaBreakdown(item.tvaBreakdown);
        return {
            taux: "MIXED",
            montantTTC: item.montantTTC,
            montantHT: String((ttc - totTva).toFixed(2)),
            tvaBreakdown: item.tvaBreakdown,
        };
    }

    const taux = parseFloat(item.taux) || 0;
    return {
        taux: item.taux,
        montantTTC: item.montantTTC,
        montantHT: String(ttcToHt(ttc, taux)),
    };
};

const normalizeTvaItem = (it: any): TvaItem => {
    // ✅ Cas MIXED — préserver le breakdown si présent
    if (it.taux === "MIXED" && it.tvaBreakdown) {
        return {
            taux: "MIXED",
            montantTTC: String(it.montantTTC || ""),
            tvaBreakdown: { ...it.tvaBreakdown },
        };
    }
    if (it.montantTTC !== undefined && it.montantTTC !== "") {
        return { taux: String(it.taux ?? "20"), montantTTC: String(it.montantTTC) };
    }
    if (it.montantHT !== undefined && it.montantHT !== "") {
        const ht = parseFloat(it.montantHT) || 0;
        const taux = parseFloat(it.taux) || 0;
        const ttc = ht > 0 ? parseFloat((ht * (1 + taux / 100)).toFixed(2)) : 0;
        return { taux: String(it.taux ?? "20"), montantTTC: ttc > 0 ? String(ttc) : "" };
    }
    return { taux: String(it.taux ?? "20"), montantTTC: "" };
};

const isExcelTvaCategory = (categorie: string): boolean =>
    CATS_EXCEL_TVA.some(c => categorie.toLowerCase().includes(c));

async function fileToMeta(file: File): Promise<FileMeta> {
    const meta: FileMeta = { name: file.name, type: file.type, size: file.size };
    if (file.type.startsWith("image/")) {
        try {
            meta.preview = await new Promise<string>((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = () => resolve(reader.result as string);
                reader.onerror = reject;
                reader.readAsDataURL(file);
            });
        } catch { }
    }
    return meta;
}

function calcIndemnite(km: number, cv: number): number {
    const b = BAREME_KM.find(r => r.cv === cv) ?? BAREME_KM[4];
    if (km <= 0) return 0;
    if (km <= 5000) return parseFloat((km * b.t1).toFixed(2));
    if (km <= 20000) return parseFloat((km * b.t2_a + b.t2_b).toFixed(2));
    return parseFloat((km * b.t3).toFixed(2));
}
function getTranche(km: number) { return km <= 0 ? 0 : km <= 5000 ? 1 : km <= 20000 ? 2 : 3; }
    // ── Helper — vérifie qu'une date n'est pas dans un mois futur ──────────
    function isDateFutureMonth(dateStr: string): boolean {
        if (!dateStr) return false;
        const d = new Date(dateStr);
        if (isNaN(d.getTime())) return false;
        const now = new Date();
        // Date du 1er jour du mois suivant
        const firstDayNextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
        return d >= firstDayNextMonth;
    }

    // Retourne la date max autorisée pour les inputs (dernier jour du mois courant)
    function getMaxAllowedDate(): string {
        const now = new Date();
        const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0);
        const y = lastDay.getFullYear();
        const m = String(lastDay.getMonth() + 1).padStart(2, '0');
        const d = String(lastDay.getDate()).padStart(2, '0');
        return `${y}-${m}-${d}`;
    }

// ── PROFIL VÉHICULE — interface partagée ─────────────────
interface ProfilVehiculeData {
    chevaux: number;
    marque: string;
    modele: string;
    immatriculation: string;
}

function newDepense(defaultChevaux = 7): Depense {
    return {
        id: Math.random(), categorie: "", date: "", libelle: "", description: "",
        km: "", chevaux: defaultChevaux, tvaItems: [{ taux: "20", montantTTC: "" }],
        nombreParticipants: "", participants: [{ nom: "", prenom: "", societe: "" }],
        files: [], filesMeta: [], qrLink: null, qrUploaded: false, qrNoteRef: "", qrFiles: [],
         nuits: "",
    };
}

function serializeDepenses(depenses: Depense[]) {
    return depenses.map(d => ({
        ...d,
        files: [],
        filesMeta: d.filesMeta ?? [],
        qrFiles: d.qrFiles ?? [],
        tvaItems: d.tvaItems.map(tvaItemToBackend),
    }));
}

// ── FILES STORE ───────────────────────────────────────
const filesStore = new Map<number, File[]>();
const getStoredFiles = (id: number): File[] => filesStore.get(id) ?? [];
const setStoredFiles = (id: number, files: File[]) => filesStore.set(id, files);

// ── CSS ───────────────────────────────────────────────
const css = `
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700;800&family=DM+Mono:wght@400;500&display=swap');

.nn * { box-sizing: border-box; }
.nn { font-family: 'DM Sans', sans-serif; }

.nn-layout { display: flex; gap: 20px; align-items: flex-start; }
.nn-main   { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.nn-side   { width: 220px; flex-shrink: 0; position: sticky; top: 20px; display: flex; flex-direction: column; gap: 10px; }

.nn-meta {
  background: var(--bg-card, #fff);
  border: 1px solid var(--border-card, rgba(0,0,0,.08));
  border-radius: 12px; padding: 14px 16px;
  display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px;
}
.nn-meta-field label {
  display: block; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-secondary, #6b7280); margin-bottom: 4px;
}
.nn-meta-field label span { color: #ef4444; }
.nn-input {
  background: var(--bg-input, #f9f9fa);
  border: 1px solid rgba(0,0,0,.09); border-radius: 7px; padding: 7px 10px;
  font-size: 13px; font-family: 'DM Sans', sans-serif;
  color: var(--text-primary, #111); width: 100%; outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.nn-input:focus { border-color: rgba(99,102,241,.5); box-shadow: 0 0 0 3px rgba(99,102,241,.1); }
.nn-input::placeholder { color: var(--text-secondary, #9ca3af); }
select.nn-input {
  appearance: none; cursor: pointer; padding-right: 24px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center;
}

.nn-topbar { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.nn-topbar-left { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.nn-save { font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 8px; }
.nn-save.saving { background: #eff6ff; color: #3b82f6; }
.nn-save.saved  { background: #f0fdf4; color: #15803d; }
.nn-save.error  { background: #fef2f2; color: #dc2626; }

.nn-bro-bar {
  background: var(--bg-card, #fff);
  border: 1px solid var(--border-card, rgba(0,0,0,.08));
  border-radius: 10px; overflow: hidden;
}
.nn-bro-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 14px; border-bottom: 1px solid rgba(0,0,0,.05);
  font-size: 11px; font-weight: 700; color: var(--text-secondary, #6b7280);
  text-transform: uppercase; letter-spacing: .05em; flex-wrap: wrap; gap: 6px;
}
.nn-bro-row {
  display: flex; align-items: center; padding: 8px 14px; gap: 8px;
  border-bottom: 1px solid rgba(0,0,0,.04); flex-wrap: wrap;
}
.nn-bro-row:last-child { border-bottom: none; }
.nn-bro-row.active { background: #eef2ff; }
.nn-bro-name { font-size: 12px; font-weight: 700; flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nn-bro-active-tag { background: #6366f1; color: #fff; font-size: 9px; font-weight: 800; padding: 1px 5px; border-radius: 4px; margin-left: 5px; }
.nn-bro-date { font-size: 10px; color: var(--text-secondary, #9ca3af); white-space: nowrap; }

.nn-active-bro {
  background: #eef2ff; border: 1px solid #c7d2fe;
  border-radius: 10px; padding: 8px 14px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.nn-active-bro-name { font-size: 12px; font-weight: 700; color: #4f46e5; }
.nn-active-bro-date { font-size: 10px; color: #6366f1; margin-top: 1px; }

.nn-card {
  background: var(--bg-card, #fff);
  border: 1px solid var(--border-card, rgba(0,0,0,.08));
  border-radius: 12px; overflow: hidden;
  box-shadow: 0 1px 3px rgba(0,0,0,.04); transition: box-shadow .15s;
}
.nn-card:hover { box-shadow: 0 2px 8px rgba(0,0,0,.08); }
.nn-card.expanded { border-color: rgba(99,102,241,.3); box-shadow: 0 0 0 2px rgba(99,102,241,.08), 0 2px 8px rgba(0,0,0,.06); }
.nn-card.has-error { border-color: rgba(239,68,68,.4); }

.nn-acc-head {
  display: flex; align-items: center; padding: 10px 14px;
  cursor: pointer; user-select: none; gap: 10px; transition: background .12s;
}
.nn-acc-head:hover { background: rgba(0,0,0,.02); }
.nn-acc-icon {
  width: 30px; height: 30px; border-radius: 8px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; font-size: 15px;
  background: linear-gradient(135deg, #f1f5f9, #e2e8f0);
}
.nn-acc-info { flex: 1; min-width: 0; }
.nn-acc-title { font-size: 13px; font-weight: 700; color: var(--text-primary, #111); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nn-acc-sub   { font-size: 11px; color: var(--text-secondary, #6b7280); margin-top: 1px; }
.nn-acc-tags  { display: flex; align-items: center; gap: 6px; flex-shrink: 0; flex-wrap: wrap; }
.nn-tag-amt  { background: #eef2ff; color: #6366f1; font-size: 11px; font-weight: 800; padding: 2px 8px; border-radius: 12px; font-family: 'DM Mono', monospace; }
.nn-tag-file { background: #f0fdf4; color: #16a34a; font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 12px; }
.nn-tag-err  { background: #fef2f2; color: #ef4444; font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 12px; }
.nn-chevron  { font-size: 11px; color: var(--text-secondary, #9ca3af); transition: transform .2s; flex-shrink: 0; }
.nn-chevron.open { transform: rotate(180deg); }

.nn-acc-body {
  padding: 0 14px 14px; border-top: 1px solid rgba(0,0,0,.06);
  display: flex; flex-direction: column; gap: 10px;
}

.nn-row { display: flex; gap: 8px; align-items: flex-end; }
.nn-row.g3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.nn-field { display: flex; flex-direction: column; }
.nn-fl {
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--text-secondary, #6b7280);
  margin-bottom: 4px; display: block;
}
.nn-fl span { color: #ef4444; }

/* ── KM ── */
.nn-km-box { background: rgba(124,58,237,.05); border: 1.5px solid rgba(124,58,237,.18); border-radius: 9px; padding: 12px; }
.nn-km-title { font-size: 12px; font-weight: 800; color: #7c3aed; margin-bottom: 8px; }
.nn-km-bareme { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 10px; }
.nn-km-bareme-item {
  display: flex; align-items: center; gap: 5px; padding: 5px 9px; border-radius: 6px;
  cursor: pointer; border: 1.5px solid transparent; background: rgba(0,0,0,.03); transition: all .12s;
  flex: 1; min-width: 90px;
}
.nn-km-bareme-item:hover { background: rgba(124,58,237,.08); border-color: rgba(124,58,237,.25); }
.nn-km-bareme-item.sel { background: rgba(124,58,237,.12); border-color: rgba(124,58,237,.4); }
.nn-km-bareme-label { font-size: 11px; font-weight: 700; color: var(--text-primary, #111); }
.nn-km-bareme-item.sel .nn-km-bareme-label { color: #7c3aed; }
.nn-km-bareme-rate { font-size: 10px; color: var(--text-secondary, #6b7280); font-family: 'DM Mono', monospace; }
.nn-km-bareme-item.sel .nn-km-bareme-rate { color: #7c3aed; }
.nn-km-grid { display: grid; grid-template-columns: 130px 1fr; gap: 8px; align-items: end; }
.nn-km-input-wrap { position: relative; }
.nn-km-unit { position: absolute; right: 9px; top: 50%; transform: translateY(-50%); font-size: 11px; color: #7c3aed; font-weight: 700; pointer-events: none; }
.nn-km-result {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 11px; background: linear-gradient(135deg, #7c3aed, #5b21b6);
  border-radius: 7px;
}
.nn-km-result-label { font-size: 11px; color: rgba(255,255,255,.75); font-weight: 600; }
.nn-km-result-value { font-size: 15px; font-weight: 900; color: #fff; font-family: 'DM Mono', monospace; }
.nn-km-result-detail { font-size: 10px; color: rgba(255,255,255,.7); text-align: right; margin-top: 1px; }

/* ── TVA CLASSIQUE ── */
.nn-tva-box { background: var(--bg-input, #f9f9fa); border: 1px solid rgba(0,0,0,.07); border-radius: 9px; padding: 10px; }
.nn-tva-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.nn-tva-title { font-size: 11px; font-weight: 700; color: var(--text-secondary, #6b7280); text-transform: uppercase; letter-spacing: .05em; }

.nn-tva-row {
  display: grid;
  grid-template-columns: 22px 22px 140px 1fr 90px 80px;
  gap: 5px; align-items: center; margin-bottom: 6px;
}
.nn-tva-row:last-child { margin-bottom: 0; }

.nn-tva-btn {
  width: 22px; height: 30px; border-radius: 5px; border: 1px solid;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 700; font-family: inherit; line-height: 1;
  flex-shrink: 0;
}
.nn-tva-btn.add { background: rgba(99,102,241,.1); color: #6366f1; border-color: rgba(99,102,241,.3); }
.nn-tva-btn.add:hover { background: rgba(99,102,241,.2); }
.nn-tva-btn.rm  { background: rgba(220,38,38,.08); color: #dc2626; border-color: rgba(220,38,38,.25); }
.nn-tva-btn.rm:hover  { background: rgba(220,38,38,.18); }
.nn-tva-btn:disabled  { opacity: .3; cursor: default; }

.nn-tva-computed {
  display: flex; align-items: center; justify-content: flex-end;
  height: 32px; font-size: 12px; font-weight: 700; font-family: 'DM Mono', monospace;
  background: rgba(0,0,0,.025); border-radius: 6px; padding: 0 8px;
}
.nn-tva-computed.ttc { color: #6366f1; }
.nn-tva-computed.tva { color: #4f46e5; }
.nn-tva-computed.na  { color: var(--text-secondary, #9ca3af); font-weight: 400; }

.nn-tva-total {
  margin-top: 8px; padding: 8px 10px; background: rgba(0,0,0,.03); border-radius: 6px;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px;
}
.nn-tva-total-cell { text-align: center; }
.nn-tva-total-cell + .nn-tva-total-cell { border-left: 1px solid rgba(0,0,0,.06); }
.nn-tva-total-lbl { font-size: 9px; font-weight: 700; text-transform: uppercase; color: var(--text-secondary, #6b7280); margin-bottom: 1px; }
.nn-tva-total-val { font-size: 12px; font-weight: 900; font-family: 'DM Mono', monospace; }

/* ── TVA EXCEL — saisie manuelle de toutes les colonnes ── */
.nn-tva-excel-wrap { overflow-x: auto; }
.nn-tva-excel {
  width: 100%; border-collapse: collapse;
  font-size: 12px; font-family: 'DM Mono', monospace;
  border: 1px solid rgba(0,0,0,.12); border-radius: 8px; overflow: hidden;
  min-width: 620px;
}
.nn-tva-excel thead tr { background: rgba(0,0,0,.04); }
.nn-tva-excel th {
  padding: 7px 9px; text-align: right; font-size: 10px;
  font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: #6b7280; border-bottom: 1.5px solid rgba(0,0,0,.12);
  white-space: nowrap; font-family: 'DM Sans', sans-serif;
}
.nn-tva-excel th:first-child { text-align: left; }

/* Séparateur visuel après TTC */
.nn-tva-excel th.ttc-col  { color: #6366f1; border-right: 2px solid rgba(99,102,241,.35); }
.nn-tva-excel td.ttc-col  { color: #6366f1; font-weight: 700; border-right: 2px solid rgba(99,102,241,.2); }

/* Colonnes TVA */
.nn-tva-excel th.tva-col  { color: #4f46e5; border-left: 1px dashed rgba(99,102,241,.2); }
.nn-tva-excel td.tva-col  { border-left: 1px dashed rgba(99,102,241,.12); }

/* Séparateur avant HT */
.nn-tva-excel th.ht-col   { color: #7c3aed; border-left: 2px solid rgba(124,58,237,.25); }
.nn-tva-excel td.ht-col   { color: #7c3aed; font-weight: 700; border-left: 2px solid rgba(124,58,237,.18); }

.nn-tva-excel td {
  padding: 5px 9px; text-align: right;
  border-bottom: 1px solid rgba(0,0,0,.05);
}
.nn-tva-excel td:first-child { text-align: left; font-family: 'DM Sans', sans-serif; }

/* Ligne total footer */
.nn-tva-excel tfoot tr { background: rgba(99,102,241,.05); }
.nn-tva-excel tfoot td {
  font-weight: 800; font-size: 11px;
  border-top: 1.5px solid rgba(0,0,0,.12);
  font-family: 'DM Sans', sans-serif;
  text-align: right;
}
.nn-tva-excel tfoot td:first-child { text-align: left; }
.nn-tva-excel tfoot td.ttc-col { color: #6366f1; border-right: 2px solid rgba(99,102,241,.2); }
.nn-tva-excel tfoot td.tva-col { color: #4f46e5; border-left: 1px dashed rgba(99,102,241,.12); }
.nn-tva-excel tfoot td.ht-col  { color: #7c3aed; border-left: 2px solid rgba(124,58,237,.18); }

/* Input dans cellule Excel */
.nn-tva-excel-input {
  width: 100%; border: none; background: transparent;
  text-align: right; font-family: 'DM Mono', monospace;
  font-size: 12px; outline: none; color: #111;
  padding: 2px 4px; min-width: 70px;
}
.nn-tva-excel-input:focus {
  background: rgba(99,102,241,.06); border-radius: 4px;
}
.nn-tva-excel-input::placeholder { color: #d1d5db; }

/* Highlight readonly computed cells */
.nn-tva-excel-computed {
  display: block; text-align: right; font-family: 'DM Mono', monospace;
  font-size: 12px; padding: 2px 4px;
  color: var(--text-secondary, #9ca3af);
}
.nn-tva-excel-computed.has-value { color: inherit; }

/* ── REPAS ── */
.nn-repas-box { background: rgba(251,191,36,.06); border: 1.5px solid rgba(251,191,36,.3); border-radius: 9px; padding: 10px; }
.nn-repas-title { font-size: 11px; font-weight: 800; color: #92400e; margin-bottom: 8px; text-transform: uppercase; letter-spacing: .04em; }
.nn-participant-row { display: grid; grid-template-columns: 1fr 1fr 1fr 26px 26px; gap: 6px; align-items: center; margin-bottom: 5px; }

/* Bandeau info repas (affiché au choix de catégorie et en alerte) */
.nn-repas-info {
  background: rgba(251,191,36,.12); border: 1.5px solid rgba(251,191,36,.45);
  border-radius: 8px; padding: 9px 12px; font-size: 11px; font-weight: 600; color: #92400e;
  display: flex; align-items: flex-start; gap: 8px; margin-bottom: 8px;
}
.nn-repas-info.alert {
  background: rgba(239,68,68,.07); border-color: rgba(239,68,68,.4); color: #dc2626;
}
.nn-repas-info.warn {
  background: rgba(245,158,11,.08); border-color: rgba(245,158,11,.4); color: #b45309;
}
.nn-repas-info-icon { font-size: 15px; flex-shrink: 0; margin-top: 1px; }

/* Boutons +/- participant */
.nn-p-btn {
  width: 26px; height: 30px; border-radius: 5px; border: 1px solid;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 700; font-family: inherit; line-height: 1; flex-shrink: 0;
}
.nn-p-btn.add { background: rgba(251,191,36,.12); color: #92400e; border-color: rgba(251,191,36,.5); }
.nn-p-btn.add:hover { background: rgba(251,191,36,.25); }
.nn-p-btn.rm  { background: rgba(220,38,38,.08); color: #dc2626; border-color: rgba(220,38,38,.25); }
.nn-p-btn.rm:hover { background: rgba(220,38,38,.18); }

/* Repas seul badge */
.nn-repas-seul {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(251,191,36,.15); border: 1px solid rgba(251,191,36,.4);
  border-radius: 20px; padding: 4px 12px; font-size: 11px; font-weight: 700; color: #92400e;
  margin-top: 4px;
}

/* ── KM NOTICE ── */
.nn-km-notice {
  background: rgba(124,58,237,.06); border: 1.5px solid rgba(124,58,237,.22);
  border-radius: 8px; padding: 10px 13px; font-size: 11px; font-weight: 500;
  color: #5b21b6; line-height: 1.55; margin-bottom: 10px;
}
.nn-km-notice a { color: #7c3aed; font-weight: 700; }

/* ── FILES ── */
.nn-file-area { margin-top: 2px; }
.nn-drop {
  border: 1.5px dashed rgba(0,0,0,.12); border-radius: 7px; padding: 10px 14px;
  text-align: center; cursor: pointer; font-size: 12px;
  color: var(--text-secondary, #9ca3af); font-weight: 500; transition: all .15s;
}
.nn-drop:hover { border-color: rgba(99,102,241,.4); color: #6366f1; }
.nn-drop.ok { border-color: rgba(22,163,74,.5); color: #16a34a; background: rgba(22,163,74,.03); }
.nn-file-grid { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.nn-file-thumb {
  position: relative; border-radius: 8px; overflow: visible; width: 72px;
  border: 1.5px solid rgba(0,0,0,.09); background: var(--bg-input, #f9f9fa);
  cursor: pointer; transition: all .15s; flex-shrink: 0;
}
.nn-file-thumb:hover { border-color: #6366f1; transform: translateY(-1px); box-shadow: 0 3px 8px rgba(99,102,241,.2); }
.nn-file-thumb.ghost  { border-color: #fde68a; background: #fffbeb; }
.nn-file-thumb.qr-file{ border-color: #e9d5ff; background: #faf5ff; }
.nn-file-preview { width: 72px; height: 52px; object-fit: cover; display: block; border-radius: 6px 6px 0 0; }
.nn-file-icon { width: 72px; height: 52px; display: flex; align-items: center; justify-content: center; font-size: 22px; }
.nn-file-label { padding: 3px 5px; font-size: 9px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nn-file-del {
  position: absolute; top: -6px; right: -6px; width: 18px; height: 18px;
  border-radius: 50%; background: #ef4444; color: #fff; border: 2px solid #fff;
  cursor: pointer; font-size: 9px; display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity .15s; z-index: 10; box-shadow: 0 1px 4px rgba(0,0,0,.25);
  font-weight: 800; line-height: 1;
}
.nn-file-thumb:hover .nn-file-del { opacity: 1; }
.nn-ghost-badge { position: absolute; top: 3px; left: 3px; background: #f59e0b; color: #fff; font-size: 7px; font-weight: 800; padding: 1px 4px; border-radius: 3px; }
.nn-qr-badge    { position: absolute; top: 3px; left: 3px; color: #fff; font-size: 7px; font-weight: 800; padding: 1px 4px; border-radius: 3px; }

.nn-qr-btn {
  width: 100%; display: flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 12px; background: rgba(124,58,237,.05);
  border: 1.5px dashed rgba(124,58,237,.3); border-radius: 7px;
  cursor: pointer; font-size: 11px; font-weight: 600; color: #7c3aed;
  font-family: inherit; transition: all .15s; margin-top: 8px;
}
.nn-qr-btn:hover { background: rgba(124,58,237,.09); border-color: rgba(124,58,237,.5); }
.nn-qr-box {
  margin-top: 8px; display: flex; flex-direction: column; align-items: center; gap: 6px;
  background: #faf5ff; border: 1px solid #e9d5ff; border-radius: 9px; padding: 12px;
}
.nn-qr-uploaded {
  margin-top: 8px; background: #f0fdf4; border: 1px solid #a7f3d0;
  border-radius: 7px; padding: 8px 12px; display: flex; align-items: center; gap: 8px;
}

.nn-btn-del-card {
  width: 100%; padding: 7px; background: transparent;
  border: 1px solid rgba(0,0,0,.08); border-radius: 7px; cursor: pointer;
  font-size: 11px; font-weight: 600; font-family: inherit;
  color: var(--text-secondary, #6b7280); transition: all .12s; margin-top: 4px;
}
.nn-btn-del-card:hover { background: rgba(220,38,38,.05); border-color: rgba(220,38,38,.2); color: #dc2626; }

.nn-btn-add-card {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  width: 100%; padding: 9px; border: 1.5px dashed rgba(0,0,0,.12); border-radius: 10px;
  background: transparent; cursor: pointer, font-size: 12px; font-weight: 700;
  color: var(--text-secondary, #6b7280); font-family: inherit; transition: all .15s;
}
.nn-btn-add-card:hover { border-color: rgba(99,102,241,.4); color: #6366f1; background: rgba(99,102,241,.03); }

.nn-recap {
  background: var(--bg-card, #fff); border: 1px solid var(--border-card, rgba(0,0,0,.08));
  border-radius: 12px; padding: 14px; box-shadow: 0 2px 10px rgba(0,0,0,.04);
}
.nn-recap-title { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .08em; color: var(--text-secondary, #6b7280); margin-bottom: 10px; }
.nn-recap-item { display: flex; align-items: center; gap: 7px; padding: 5px 7px; border-radius: 7px; background: rgba(0,0,0,.02); margin-bottom: 4px; }
.nn-recap-dot { width: 6px; height: 6px; border-radius: 50%; background: #c8933a; flex-shrink: 0; }
.nn-recap-lbl { font-size: 11px; font-weight: 700; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nn-recap-cat { font-size: 10px; color: var(--text-secondary, #6b7280); }
.nn-recap-amt { font-size: 11px; font-weight: 800; color: #6366f1; flex-shrink: 0; font-family: 'DM Mono', monospace; }
.nn-recap-totals { border-top: 1px solid rgba(0,0,0,.06); margin-top: 8px; padding-top: 8px; }
.nn-recap-row { display: flex; justify-content: space-between; padding: 3px 0; font-size: 11px; color: var(--text-secondary, #6b7280); font-weight: 500; }
.nn-recap-main { display: flex; justify-content: space-between; padding: 7px 0 4px; font-size: 14px; font-weight: 800; }
.nn-recap-main-val { color: #6366f1; font-family: 'DM Mono', monospace; }
.nn-btn-recap-sub {
  width: 100%; padding: 10px; background: linear-gradient(135deg, #111, #333);
  color: #fff; border: none; border-radius: 9px; font-size: 12px; font-weight: 800;
  cursor: pointer; font-family: inherit; margin-top: 8px; transition: opacity .15s;
}
.nn-btn-recap-sub:hover:not(:disabled) { opacity: .88; }
.nn-btn-recap-sub:disabled { opacity: .5; cursor: not-allowed; }
.nn-recap-subnote { font-size: 10px; color: var(--text-secondary, #9ca3af); text-align: center; margin-top: 5px; }

.nn-error {
  padding: 10px 14px; background: #fef2f2; border: 1.5px solid #fecaca;
  border-radius: 9px; color: #dc2626; font-size: 12px; font-weight: 600;
}

.nn-nuits-box {
  background: rgba(99,102,241,.05); border: 1.5px solid rgba(99,102,241,.2);
  border-radius: 8px; padding: 10px 13px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 2px;
}
.nn-nuits-label { font-size: 11px; font-weight: 700; color: #4f46e5; }
.nn-nuits-par-nuit {
  font-size: 12px; font-weight: 800; font-family: 'DM Mono', monospace;
  color: #7c3aed; background: rgba(124,58,237,.08);
  border-radius: 6px; padding: 3px 9px;
}

.nn-btn-sm { font-size: 10px; font-weight: 700; padding: 3px 8px; border-radius: 5px; cursor: pointer; font-family: inherit; border: 1px solid; }
.nn-btn-sm.indigo { background: rgba(99,102,241,.1); color: #6366f1; border-color: rgba(99,102,241,.25); }
.nn-btn-sm.green  { background: rgba(22,163,74,.1);  color: #16a34a; border-color: rgba(22,163,74,.25); }
.nn-btn-sm.red    { background: rgba(220,38,38,.1);  color: #dc2626; border-color: rgba(220,38,38,.25); }

@keyframes nn-spin { to { transform: rotate(360deg); } }
.nn-spinner { width: 12px; height: 12px; border: 2px solid rgba(255,255,255,.4); border-top-color: #fff; border-radius: 50%; animation: nn-spin .7s linear infinite; flex-shrink: 0; }

@media(max-width: 900px) { .nn-layout { flex-direction: column; } .nn-side { width: 100%; position: static; } }
@media(max-width: 600px) { .nn-meta { grid-template-columns: 1fr 1fr; } .nn-tva-row { grid-template-columns: 22px 22px 110px 1fr 70px 60px; } }
@media(max-width: 480px) { .nn-meta { grid-template-columns: 1fr; } .nn-row.g3 { grid-template-columns: 1fr 1fr; } }
`;

// ── VIEWER MODAL ──────────────────────────────────────
type ViewerKind = "file" | "ghost" | "qr";
interface ViewerTarget { src: string; name: string; type: string; size: number; isGhost: boolean; isQr: boolean; isReal: boolean; externalUrl?: string; }

function FileViewer({ target, onClose, onDelete, apiBaseUrl }: {
    target: ViewerTarget; onClose: () => void; onDelete?: () => void; apiBaseUrl: string;
}) {
    const isPdf = target.type === "application/pdf" || /\.pdf$/i.test(target.name);
    const isImg = target.type.startsWith("image/") || /\.(jpg|jpeg|png|gif|webp)$/i.test(target.name);
    useEffect(() => {
        const h = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); };
        window.addEventListener("keydown", h);
        return () => window.removeEventListener("keydown", h);
    }, [onClose]);
    return (
        <div onClick={e => { if (e.target === e.currentTarget) onClose(); }}
            style={{ position: "fixed", inset: 0, zIndex: 9999, background: "rgba(0,0,0,.82)", backdropFilter: "blur(6px)", display: "flex", alignItems: "center", justifyContent: "center", padding: 20 }}>
            <div onClick={e => e.stopPropagation()}
                style={{ background: "#1a1a2e", borderRadius: 16, overflow: "hidden", maxWidth: "92vw", maxHeight: "92vh", display: "flex", flexDirection: "column", boxShadow: "0 32px 80px rgba(0,0,0,.65)", minWidth: 320 }}>
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "12px 18px", background: "#16213e", borderBottom: "1px solid rgba(255,255,255,.07)", gap: 12 }}>
                    <span style={{ fontSize: 13, fontWeight: 700, color: "#e2e8f0", flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{target.name}</span>
                    <button onClick={onClose} style={{ width: 30, height: 30, borderRadius: 7, border: "none", background: "rgba(255,255,255,.1)", color: "#e2e8f0", cursor: "pointer", fontSize: 14, display: "flex", alignItems: "center", justifyContent: "center" }}>✕</button>
                </div>
                <div style={{ flex: 1, overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", minHeight: 0, background: "#0f0f1a" }}>
                    {!target.isReal && !target.externalUrl && (
                        <div style={{ color: "#94a3b8", padding: "40px 32px", fontSize: 13, textAlign: "center" }}>
                            <div style={{ fontSize: 36, marginBottom: 12 }}>📄</div>
                            <div style={{ fontWeight: 700, color: "#e2e8f0", marginBottom: 6 }}>{target.name}</div>
                            {target.isGhost && <div style={{ color: "#fbbf24" }}>⚠ Fichier d'une session précédente — re-joindre</div>}
                        </div>
                    )}
                    {target.isQr && target.externalUrl && isPdf && <iframe src={`${apiBaseUrl}/api/proxy-pdf?url=${encodeURIComponent(target.externalUrl)}`} title={target.name} style={{ width: "80vw", height: "75vh", border: "none", background: "#fff" }} />}
                    {target.isQr && target.externalUrl && isImg && <img src={`${apiBaseUrl}/api/proxy-pdf?url=${encodeURIComponent(target.externalUrl)}`} alt={target.name} style={{ maxWidth: "100%", maxHeight: "75vh", objectFit: "contain" }} />}
                    {!target.isQr && target.isReal && isPdf && <iframe src={target.src} title={target.name} style={{ width: "80vw", height: "75vh", border: "none", background: "#fff" }} />}
                    {!target.isQr && target.isReal && isImg && <img src={target.src} alt={target.name} style={{ maxWidth: "100%", maxHeight: "75vh", objectFit: "contain" }} />}
                </div>
                <div style={{ padding: "10px 18px", borderTop: "1px solid rgba(255,255,255,.06)", display: "flex", alignItems: "center", justifyContent: "space-between", background: "#16213e", gap: 8, flexWrap: "wrap" }}>
                    <span style={{ fontSize: 11, color: "#94a3b8" }}>{target.isGhost ? "⚠ Session précédente" : target.isQr ? "📱 Via QR" : ""}</span>
                    <div style={{ display: "flex", gap: 8 }}>
                        {target.externalUrl && <a href={target.externalUrl} target="_blank" rel="noreferrer" style={{ padding: "5px 12px", background: "rgba(99,102,241,.15)", border: "1px solid rgba(99,102,241,.3)", borderRadius: 6, color: "#818cf8", fontSize: 11, fontWeight: 700, textDecoration: "none" }}>↗ Ouvrir</a>}
                        {onDelete && <button onClick={() => { onDelete(); onClose(); }} style={{ padding: "5px 12px", background: "rgba(239,68,68,.12)", border: "1px solid rgba(239,68,68,.3)", borderRadius: 6, color: "#f87171", fontSize: 11, fontWeight: 700, cursor: "pointer", fontFamily: "inherit" }}>🗑 Supprimer</button>}
                    </div>
                </div>
            </div>
        </div>
    );
}

// ── FILE GRID ─────────────────────────────────────────
function FileGrid({ files, ghostMetas, qrFiles, onRemoveFile, onRemoveMeta, onRemoveQr, apiBaseUrl }: {
    files: File[]; ghostMetas: FileMeta[]; qrFiles: QrFileMeta[];
    onRemoveFile: (i: number) => void;
    onRemoveMeta: (i: number) => void;
    onRemoveQr: (i: number) => void;
    apiBaseUrl: string;
}) {
    const [viewer, setViewer] = useState<(ViewerTarget & { kind: ViewerKind; idx: number }) | null>(null);
    const objUrlsRef = useRef<Map<number, string>>(new Map());
    useEffect(() => { return () => { objUrlsRef.current.forEach(u => URL.revokeObjectURL(u)); }; }, []);
    const getObjUrl = (f: File, idx: number) => {
        if (!objUrlsRef.current.has(idx)) objUrlsRef.current.set(idx, URL.createObjectURL(f));
        return objUrlsRef.current.get(idx)!;
    };
    const total = files.length + ghostMetas.length + qrFiles.length;
    if (total === 0) return null;
    return (
        <>
            {viewer && (
                <FileViewer
                    target={viewer}
                    onClose={() => setViewer(null)}
                    apiBaseUrl={apiBaseUrl}
                    onDelete={() => {
                        if (viewer.kind === "file") onRemoveFile(viewer.idx);
                        else if (viewer.kind === "ghost") onRemoveMeta(viewer.idx);
                        else if (viewer.kind === "qr") onRemoveQr(viewer.idx);
                    }}
                />
            )}
            <div className="nn-file-grid">
                {files.map((f, i) => (
                    <div key={`f-${i}`} className="nn-file-thumb"
                        onClick={() => setViewer({ src: getObjUrl(f, i), name: f.name, type: f.type, size: f.size, isGhost: false, isQr: false, isReal: true, kind: "file", idx: i })}>
                        {f.type.startsWith("image/") ? <img src={getObjUrl(f, i)} alt={f.name} className="nn-file-preview" /> : <div className="nn-file-icon">{f.type === "application/pdf" ? "📄" : "📎"}</div>}
                        <div className="nn-file-label">{f.name}</div>
                        <button className="nn-file-del" onClick={e => { e.stopPropagation(); onRemoveFile(i); }}>✕</button>
                    </div>
                ))}
                {ghostMetas.map((m, i) => (
                    <div key={`g-${i}`} className="nn-file-thumb ghost"
                        onClick={() => setViewer({ src: m.preview || "", name: m.name, type: m.type, size: m.size, isGhost: true, isQr: false, isReal: m.type.startsWith("image/") && !!m.preview, kind: "ghost", idx: i })}>
                        <div className="nn-ghost-badge">⚠</div>
                        {m.preview ? <img src={m.preview} alt={m.name} className="nn-file-preview" /> : <div className="nn-file-icon">{m.type === "application/pdf" ? "📄" : "📎"}</div>}
                        <div className="nn-file-label" style={{ color: "#92400e" }}>{m.name}</div>
                        <button className="nn-file-del" onClick={e => { e.stopPropagation(); onRemoveMeta(i); }}>✕</button>
                    </div>
                ))}
                {qrFiles.map((qf, i) => {
                    const isQrScan = !qf.origin || qf.origin === 'qr';
                    const badgeBg = isQrScan ? '#7c3aed' : '#6366f1';
                    const badgeLabel = isQrScan ? '📱' : '📎';
                    return (
                        <div key={`qr-${i}`} className="nn-file-thumb qr-file"
                            onClick={() => setViewer({
                                src: qf.uploadUrl, name: qf.fileName,
                                type: /\.(jpg|jpeg|png|gif|webp)$/i.test(qf.fileName) ? "image/jpeg" : "application/pdf",
                                size: 0, isGhost: false, isQr: true, isReal: true,
                                externalUrl: qf.uploadUrl, kind: "qr", idx: i
                            })}>
                            <div className="nn-qr-badge" style={{ background: badgeBg }}>{badgeLabel}</div>
                            <div className="nn-file-icon" style={{ color: "#7c3aed" }}>
                                {/\.(jpg|jpeg|png|gif|webp)$/i.test(qf.fileName) ? "🖼️" : "📄"}
                            </div>
                            <div className="nn-file-label" style={{ color: "#7c3aed" }}>{qf.fileName}</div>
                            <button className="nn-file-del" onClick={e => { e.stopPropagation(); onRemoveQr(i); }}>✕</button>
                        </div>
                    );
                })}
            </div>
        </>
    );
}

// ── TVA EXCEL TABLE — saisie manuelle de toutes les colonnes ─
interface ExcelRow {
    ttc: string;
    tva21: string;
    tva55: string;
    tva10: string;
    tva20: string;
}

function TvaExcelTable({ tvaItems, onUpdate }: {
    tvaItems: TvaItem[];
    onUpdate: (items: TvaItem[]) => void;
}) {
    // ✅ Reconstruction des ExcelRow depuis les TvaItem
    // 1 item = 1 ligne du tableau Excel
    const initRows = (): ExcelRow[] => {
        if (tvaItems.length === 0) {
            return [{ ttc: "", tva21: "", tva55: "", tva10: "", tva20: "" }];
        }

        const rows = tvaItems
            .filter(it => parseFloat(it.montantTTC || "0") > 0 || it.montantTTC === "")
            .map(it => {
                const row: ExcelRow = { ttc: it.montantTTC || "", tva21: "", tva55: "", tva10: "", tva20: "" };

                if (it.taux === "MIXED" && it.tvaBreakdown) {
                    // ✅ Item MIXED : on a la répartition complète
                    if (it.tvaBreakdown.tva21) row.tva21 = it.tvaBreakdown.tva21;
                    if (it.tvaBreakdown.tva55) row.tva55 = it.tvaBreakdown.tva55;
                    if (it.tvaBreakdown.tva10) row.tva10 = it.tvaBreakdown.tva10;
                    if (it.tvaBreakdown.tva20) row.tva20 = it.tvaBreakdown.tva20;
                } else {
                    // Item simple : on calcule la TVA depuis le taux + TTC
                    const ttc = parseFloat(it.montantTTC) || 0;
                    const taux = parseFloat(it.taux) || 0;
                    if (ttc > 0 && taux > 0) {
                        const ht = ttc / (1 + taux / 100);
                        const tva = ttc - ht;
                        const tvaStr = tva.toFixed(2);
                        if (it.taux === "2.1") row.tva21 = tvaStr;
                        else if (it.taux === "5.5") row.tva55 = tvaStr;
                        else if (it.taux === "10") row.tva10 = tvaStr;
                        else if (it.taux === "20") row.tva20 = tvaStr;
                    }
                }
                return row;
            });

        return rows.length > 0 ? rows : [{ ttc: "", tva21: "", tva55: "", tva10: "", tva20: "" }];
    };

    const [rows, setRows] = useState<ExcelRow[]>(initRows);

    // ✅ FIX : 1 ligne du tableau = 1 SEUL item dans tvaItems
    const syncToParent = (newRows: ExcelRow[]) => {
        const items: TvaItem[] = [];

        newRows.forEach(row => {
            const ttc = parseFloat(row.ttc) || 0;
            if (ttc <= 0 && !row.ttc) return; // ligne vide → on saute

            const t21 = parseFloat(row.tva21) || 0;
            const t55 = parseFloat(row.tva55) || 0;
            const t10 = parseFloat(row.tva10) || 0;
            const t20 = parseFloat(row.tva20) || 0;

            // Compter combien de taux ont une valeur > 0
            const tauxRemplis = [
                { val: t21, tauxStr: "2.1", key: "tva21" },
                { val: t55, tauxStr: "5.5", key: "tva55" },
                { val: t10, tauxStr: "10", key: "tva10" },
                { val: t20, tauxStr: "20", key: "tva20" },
            ].filter(t => t.val > 0);

            if (tauxRemplis.length === 0) {
                // Aucune TVA → ligne TTC pure (taux 0)
                items.push({ taux: "0", montantTTC: row.ttc });
            } else if (tauxRemplis.length === 1) {
                // Un seul taux → format simple
                items.push({ taux: tauxRemplis[0].tauxStr, montantTTC: row.ttc });
            } else {
                // ✅ Plusieurs taux → UN seul item avec breakdown
                items.push({
                    taux: "MIXED",
                    montantTTC: row.ttc,
                    tvaBreakdown: {
                        ...(t21 > 0 && { tva21: row.tva21 }),
                        ...(t55 > 0 && { tva55: row.tva55 }),
                        ...(t10 > 0 && { tva10: row.tva10 }),
                        ...(t20 > 0 && { tva20: row.tva20 }),
                    },
                });
            }
        });

        if (items.length === 0) {
            items.push({ taux: "20", montantTTC: "" });
        }

        onUpdate(items);
    };

    const updateRow = (idx: number, field: keyof ExcelRow, val: string) => {
        const newRows = rows.map((r, i) => i === idx ? { ...r, [field]: val } : r);
        setRows(newRows);
        syncToParent(newRows);
    };

    const addRow = () => {
        const newRows = [...rows, { ttc: "", tva21: "", tva55: "", tva10: "", tva20: "" }];
        setRows(newRows);
        syncToParent(newRows);
    };

    const removeRow = (idx: number) => {
        if (rows.length <= 1) return;
        const newRows = rows.filter((_, i) => i !== idx);
        setRows(newRows);
        syncToParent(newRows);
    };

    const fmtN = (v: number) =>
        v !== 0
            ? new Intl.NumberFormat("fr-FR", { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(v)
            : "0,00";

    const totals = rows.reduce(
        (acc, r) => {
            const ttc = parseFloat(r.ttc) || 0;
            const t21 = parseFloat(r.tva21) || 0;
            const t55 = parseFloat(r.tva55) || 0;
            const t10 = parseFloat(r.tva10) || 0;
            const t20 = parseFloat(r.tva20) || 0;
            const sumTva = t21 + t55 + t10 + t20;
            const ht = ttc - sumTva;
            return {
                ttc: acc.ttc + ttc,
                tva21: acc.tva21 + t21,
                tva55: acc.tva55 + t55,
                tva10: acc.tva10 + t10,
                tva20: acc.tva20 + t20,
                ht: acc.ht + ht,
            };
        },
        { ttc: 0, tva21: 0, tva55: 0, tva10: 0, tva20: 0, ht: 0 }
    );

    return (
        <div>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 8 }}>
                <span className="nn-fl" style={{ marginBottom: 0 }}>Montants &amp; TVA</span>
                <span style={{ fontSize: 10, color: "var(--text-secondary, #9ca3af)", fontStyle: "italic" }}>
                    HT = TTC − Σ TVA
                </span>
            </div>
            <div className="nn-tva-excel-wrap">
                <table className="nn-tva-excel">
                    <thead>
                        <tr>
                            <th style={{ textAlign: "left", minWidth: 36, width: 36 }}>#</th>
                            <th className="ttc-col" style={{ minWidth: 90 }}>TTC</th>
                            {TVA_EXCEL_COLS.map(c => (
                                <th key={c.taux} className="tva-col" style={{ minWidth: 85 }}>{c.label}</th>
                            ))}
                            <th className="ht-col" style={{ minWidth: 85 }}>HT</th>
                            <th style={{ width: 28 }}></th>
                        </tr>
                    </thead>
                    <tbody>
                        {rows.map((row, idx) => {
                            const ttc = parseFloat(row.ttc) || 0;
                            const t21 = parseFloat(row.tva21) || 0;
                            const t55 = parseFloat(row.tva55) || 0;
                            const t10 = parseFloat(row.tva10) || 0;
                            const t20 = parseFloat(row.tva20) || 0;
                            const sumTva = t21 + t55 + t10 + t20;
                            const ht = ttc > 0 ? ttc - sumTva : 0;
                            return (
                                <tr key={idx}>
                                    <td style={{ color: "#9ca3af", fontSize: 10, textAlign: "left" }}>{idx + 1}</td>
                                    <td className="ttc-col" style={{ padding: "3px 4px" }}>
                                        <input
                                            type="number" min="0" step="0.01"
                                            className="nn-tva-excel-input"
                                            value={row.ttc}
                                            onChange={e => updateRow(idx, "ttc", e.target.value)}
                                            placeholder="0,00"
                                        />
                                    </td>
                                    <td className="tva-col" style={{ padding: "3px 4px" }}>
                                        <input
                                            type="number" min="0" step="0.01"
                                            className="nn-tva-excel-input"
                                            value={row.tva21}
                                            onChange={e => updateRow(idx, "tva21", e.target.value)}
                                            placeholder="0,00"
                                        />
                                    </td>
                                    <td className="tva-col" style={{ padding: "3px 4px" }}>
                                        <input
                                            type="number" min="0" step="0.01"
                                            className="nn-tva-excel-input"
                                            value={row.tva55}
                                            onChange={e => updateRow(idx, "tva55", e.target.value)}
                                            placeholder="0,00"
                                        />
                                    </td>
                                    <td className="tva-col" style={{ padding: "3px 4px" }}>
                                        <input
                                            type="number" min="0" step="0.01"
                                            className="nn-tva-excel-input"
                                            value={row.tva10}
                                            onChange={e => updateRow(idx, "tva10", e.target.value)}
                                            placeholder="0,00"
                                        />
                                    </td>
                                    <td className="tva-col" style={{ padding: "3px 4px" }}>
                                        <input
                                            type="number" min="0" step="0.01"
                                            className="nn-tva-excel-input"
                                            value={row.tva20}
                                            onChange={e => updateRow(idx, "tva20", e.target.value)}
                                            placeholder="0,00"
                                        />
                                    </td>
                                    <td className="ht-col">
                                        <span className={`nn-tva-excel-computed${ht !== 0 ? " has-value" : ""}`}>
                                            {fmtN(ht)}
                                        </span>
                                    </td>
                                    <td style={{ padding: "2px 4px", textAlign: "center" }}>
                                        {rows.length > 1 && (
                                            <button
                                                type="button"
                                                onClick={() => removeRow(idx)}
                                                style={{
                                                    width: 18, height: 18, borderRadius: 4,
                                                    background: "rgba(220,38,38,.08)",
                                                    border: "1px solid rgba(220,38,38,.25)",
                                                    color: "#dc2626", cursor: "pointer",
                                                    fontSize: 11, display: "flex",
                                                    alignItems: "center", justifyContent: "center",
                                                    fontFamily: "inherit", padding: 0,
                                                }}
                                                title="Supprimer cette ligne"
                                            >✕</button>
                                        )}
                                    </td>
                                </tr>
                            );
                        })}
                    </tbody>
                    <tfoot>
                        <tr>
                            <td style={{ textAlign: "left", fontSize: 10, color: "#6b7280", textTransform: "uppercase", letterSpacing: ".04em" }}>
                                Total
                            </td>
                            <td className="ttc-col">{fmtN(totals.ttc)}</td>
                            <td className="tva-col">{fmtN(totals.tva21)}</td>
                            <td className="tva-col">{fmtN(totals.tva55)}</td>
                            <td className="tva-col">{fmtN(totals.tva10)}</td>
                            <td className="tva-col">{fmtN(totals.tva20)}</td>
                            <td className="ht-col">{fmtN(totals.ht)}</td>
                            <td></td>
                        </tr>
                    </tfoot>
                </table>
            </div>
            <button
                type="button"
                onClick={addRow}
                style={{
                    marginTop: 6, background: "none",
                    border: "1px dashed rgba(99,102,241,.3)",
                    borderRadius: 5, padding: "4px 10px",
                    cursor: "pointer", fontSize: 11,
                    color: "#6366f1", fontWeight: 600,
                    fontFamily: "inherit",
                }}
            >
                + Ajouter une ligne
            </button>
        </div>
    );
}

// ── Helper — détecte si une dépense repas est de type "événementiel" ──────────
function isRepasEvenementiel(libelle: string, description: string): boolean {
    const PATTERN = /\b(ev[eè]nement|[eé]v[eè]nement|[eé]v[eè]nements)\b/i;
    const START_PATTERN = /^even/i;
    return (
        PATTERN.test(libelle) ||
        START_PATTERN.test(libelle.trim()) ||
        PATTERN.test(description || "")
    );
}

// ── DEPENSE CARD ──────────────────────────────────────
const DepenseCard = React.memo(({
    depense, index, expanded, onToggle, onUpdate, onDelete, onGenerateQR, disabled, apiBaseUrl, profilVehicule,onNavigateToProfil,
}: {
    depense: Depense; index: number; total: number; expanded: boolean;
    onToggle: (id: number) => void;
    onUpdate: (id: number, f: keyof Depense, v: any) => void;
    onDelete: (id: number) => void;
    onGenerateQR?: (id: number) => void;
    onNavigateToProfil?: () => void;
    disabled?: boolean;
    apiBaseUrl: string;
    profilVehicule?: ProfilVehiculeData | null;
    
}) => {

    const fileRef = useRef<HTMLInputElement>(null);
    const set = (f: keyof Depense, v: any) => onUpdate(depense.id, f, v);

    const isKm = depense.categorie.toLowerCase().includes("kilom");
    const isRepas = depense.categorie.toLowerCase().includes("repas");
    const isExcel = isExcelTvaCategory(depense.categorie);

    const kmNum = parseFloat(depense.km) || 0;
    const cv = typeof depense.chevaux === "number" ? depense.chevaux : parseInt(String(depense.chevaux)) || 7;
    const tranche = getTranche(kmNum);
    const ind = calcIndemnite(kmNum, cv);

    const tvaItems = depense.tvaItems?.length ? depense.tvaItems : [{ taux: "20", montantTTC: "" }];

    // ✅ Calcul TTC : 1 item = 1 TTC (plus de double-comptage)
    const ttcTotal = isKm
        ? ind
        : tvaItems.reduce((s, item) => s + (parseFloat(item.montantTTC) || 0), 0);

    // Calcul alerte repas
    const nbPersonnes = Math.max(1, (parseInt(depense.nombreParticipants) || 0) + 1);
    const ttcParPersonne = isRepas && ttcTotal > 0 ? ttcTotal / nbPersonnes : 0;

    // Détection repas événementiel — désactive l'alerte 25€
    const isEvenementiel = isRepas && isRepasEvenementiel(depense.libelle, depense.description);
    const [alerteRepasVue, setAlerteRepasVue] = useState(false);

         useEffect(() => {
                 if (isRepas && ttcParPersonne > 25 && !isEvenementiel) {
                  setAlerteRepasVue(true);
                                    }
                                }, [ttcParPersonne, isRepas, isEvenementiel]);

         useEffect(() => {
                 if (ttcTotal <= 25) setAlerteRepasVue(false);
                                }, [ttcTotal]);

                                // Remplace l'ancienne ligne repasAlerte :
    const repasAlerte = isRepas && alerteRepasVue && ttcTotal > 25 && !isEvenementiel;

    // ✅ Calcul HT — gestion du cas MIXED
    const htTotal = isKm
        ? ind
        : tvaItems.reduce((s, item) => s + itemToHt(item), 0);

    // ✅ Calcul TVA — gestion du cas MIXED
    const tvaTotal = tvaItems.reduce((s, item) => s + itemToTva(item), 0);

    const updTva = (idx: number, field: keyof TvaItem, val: string) => {
        const copy = tvaItems.map((it, i) => i === idx ? { ...it, [field]: val } : it);
        set("tvaItems", copy);
    };
    const addTvaAfter = (idx: number) => {
        const copy = [...tvaItems];
        copy.splice(idx + 1, 0, { taux: "20", montantTTC: "" });
        set("tvaItems", copy);
    };
    const removeTva = (idx: number) => {
        if (tvaItems.length <= 1) return;
        set("tvaItems", tvaItems.filter((_, i) => i !== idx));
    };

    const updP = (i: number, f: keyof Participant, v: string) => {
        const u = [...depense.participants]; u[i] = { ...u[i], [f]: v }; set("participants", u);
    };

    const handleNombreParticipants = (val: string) => {
        const n = Math.max(0, parseInt(val) || 0);
        set("nombreParticipants", val);
        const current = depense.participants ?? [];
        if (n === 0) {
            set("participants", []);
        } else if (n > current.length) {
            const added = Array.from({ length: n - current.length }, () => ({ nom: "", prenom: "", societe: "" }));
            set("participants", [...current, ...added]);
        } else {
            set("participants", current.slice(0, n));
        }
    };

    const addFiles = async (l: FileList | null) => {
        if (!l || disabled) return;
        const newFiles = Array.from(l).filter(f => ["image/jpeg", "image/jpg", "image/png", "application/pdf"].includes(f.type));
        if (!newFiles.length) return;
        const newMetas = await Promise.all(newFiles.map(fileToMeta));
        const ghostCount = Math.max(0, (depense.filesMeta ?? []).length - depense.files.length);
        const updatedFiles = [...depense.files, ...newFiles];
        setStoredFiles(depense.id, updatedFiles);
        set("files", updatedFiles);
        set("filesMeta", [...(depense.filesMeta ?? []).slice(0, ghostCount), ...(depense.filesMeta ?? []).slice(ghostCount), ...newMetas]);
    };

    const ghostCount = Math.max(0, (depense.filesMeta ?? []).length - (depense.files.length + (depense.qrFiles ?? []).length));
    const ghostMetas = (depense.filesMeta ?? []).slice(0, ghostCount);
    const totalFiles = depense.files.length + ghostCount + (depense.qrFiles ?? []).length;
    const hasError = expanded && !depense.libelle.trim();

    const baremeItem = BAREME_KM.find(b => b.cv === cv) ?? BAREME_KM[4];
    const rateLabel = tranche === 1 ? `${baremeItem.t1}` : tranche === 2 ? `(d × ${baremeItem.t2_a}) + ${baremeItem.t2_b}` : `${baremeItem.t3}`;

    const hasRealQrFile = (depense.qrFiles ?? []).some(f => !f.origin || f.origin === 'qr');

    return (
        <div className={`nn-card${expanded ? " expanded" : ""}${hasError ? " has-error" : ""}`}
            style={{ opacity: disabled ? 0.6 : 1, pointerEvents: disabled ? "none" : "auto" }}>

            <div className="nn-acc-head" onClick={() => onToggle(depense.id)}>
                <div className="nn-acc-icon">{CAT_ICONS[depense.categorie] ?? "📋"}</div>
                <div className="nn-acc-info">
                    <div className="nn-acc-title">
                        {depense.libelle || <span style={{ color: "var(--text-secondary, #9ca3af)", fontWeight: 500 }}>Dépense {index + 1}</span>}
                    </div>
                    <div className="nn-acc-sub">
                        {depense.categorie}
                        {depense.date && ` · ${new Date(depense.date).toLocaleDateString("fr-FR", { day: "2-digit", month: "short" })}`}
                    </div>
                </div>
                <div className="nn-acc-tags">
                    {ttcTotal > 0 && <span className="nn-tag-amt">{fmt(ttcTotal)}</span>}
                    {totalFiles > 0 && <span className="nn-tag-file">📎 {totalFiles}</span>}
                    {hasError && <span className="nn-tag-err">⚠ Incomplet</span>}
                </div>
                <span className={`nn-chevron${expanded ? " open" : ""}`}>▼</span>
            </div>

            {expanded && (
                <div className="nn-acc-body">

                    {isRepas && (
                        <div className="nn-repas-info" style={{ marginTop: 10, marginBottom: 0 }}>
                            <span className="nn-repas-info-icon">🍽️</span>
                            <span>
                                Catégorie <strong>Repas</strong> sélectionnée — plafond <strong>25 € / personne</strong> (sauf repas événementiel).
                                Renseignez le nombre de convives en bas pour contrôler le seuil en temps réel.
                            </span>
                        </div>
                    )}

                    <div className="nn-row g3" style={{ paddingTop: 10 }}>
                        <div className="nn-field">
                            <label className="nn-fl">Catégorie <span>*</span></label>
                            <select className="nn-input" value={depense.categorie}
                                onChange={e => {
                                    set("categorie", e.target.value);
                                    set("km", "");
                                    set("tvaItems", [{ taux: "20", montantTTC: "" }]);
                                    if (!e.target.value.toLowerCase().includes("repas")) {
                                        set("nombreParticipants", "");
                                        set("participants", [{ nom: "", prenom: "", societe: "" }]);
                                    }
                                }}>
                                <option value="">— Choisir —</option>
                                {CATEGORIES_DEFAULT.map(c => <option key={c} value={c}>{CAT_ICONS[c]} {c}</option>)}
                            </select>
                        </div>
                        <div className="nn-field">
                            <label className="nn-fl">Date <span>*</span></label>
                           <input 
                                type="date" 
                                className="nn-input" 
                                value={depense.date} 
                                max={getMaxAllowedDate()}
                                onChange={e => set("date", e.target.value)} 
                            />
                        </div>
                        <div className="nn-field">
                            <label className="nn-fl">Libellé <span>*</span></label>
                            <input className="nn-input" value={depense.libelle}
                                onChange={e => set("libelle", e.target.value)}
                                placeholder="Ex: Déjeuner client..." />
                        </div>
                    </div>

                    <div className="nn-field">
                        <label className="nn-fl">Commentaire (optionnel)</label>
                        <input className="nn-input" style={{ fontSize: 12 }} value={depense.description}
                            onChange={e => set("description", e.target.value)}
                            placeholder="Précision, contexte..." />
                    </div>

                    {/* ── KM ── */}
                    {isKm && (
                        <div className="nn-km-box">
                            <div className="nn-km-title">🚗 Barème kilométrique</div>
                            <div className="nn-km-notice">
                                📍 <strong>Rappel :</strong> pour calculer le nombre de kilomètres parcourus, la distance à prendre en compte doit être calculée sur le site{" "}
                                <a href="https://www.viamichelin.fr/" target="_blank" rel="noreferrer">viamichelin.fr</a>{" "}
                                où vous choisirez le <em>« trajet le plus rapide »</em>, en favorisant les trajets sans section à péage.
                            </div>

                     {profilVehicule && (
                                <div style={{
                                    display: "flex", alignItems: "center", gap: 10,
                                    background: "rgba(124,58,237,.07)", border: "1px solid rgba(124,58,237,.22)",
                                    borderRadius: 8, padding: "8px 12px", marginBottom: 10,
                                }}>
                                    <span style={{ fontSize: 18 }}>🚘</span>
                                    <div style={{ flex: 1 }}>
                                        <div style={{ fontSize: 11, fontWeight: 700, color: "#7c3aed" }}>
                                            Véhicule depuis votre profil — vous pouvez ajuster les CV ci-dessous
                                        </div>
                                        <div style={{ fontSize: 12, color: "#4b3f80" }}>
                                            {profilVehicule.marque} {profilVehicule.modele}
                                            {profilVehicule.immatriculation && ` · ${profilVehicule.immatriculation}`}
                                        </div>
                                    </div>
                                    <button
                                        type="button"
                                        onClick={() => onNavigateToProfil?.()}   // ← le vrai fix
                                        style={{
                                            fontSize: 10, color: "#7c3aed", background: "none",
                                            border: "none", cursor: "pointer", fontFamily: "inherit",
                                            fontWeight: 700, padding: 0, whiteSpace: "nowrap",
                                        }}>
                                        Modifier ↗
                                    </button>
                                </div>
                            )}
                            {!profilVehicule && (
                                <div style={{ fontSize: 11, color: "#f59e0b", background: "rgba(245,158,11,.08)", border: "1px solid rgba(245,158,11,.2)", borderRadius: 7, padding: "6px 10px", marginBottom: 8 }}>
                                    ⚠️ Aucun véhicule renseigné dans votre profil. <a href="/profil" style={{ color: "#d97706", fontWeight: 700 }}>Configurer maintenant ↗</a>
                                </div>
                            )}
                            {/* Sélecteur CV — toujours visible */}
                           
                               
                            <div className="nn-km-grid">
                                <div className="nn-field">
                                    <label className="nn-fl" style={{ color: "#7c3aed" }}>Kilométrage <span>*</span></label>
                                    <div className="nn-km-input-wrap">
                                        <input type="number" min="0" className="nn-input"
                                            style={{ borderColor: "rgba(124,58,237,.4)", paddingRight: 34 }}
                                            value={depense.km} onChange={e => set("km", e.target.value)} placeholder="0" />
                                        <span className="nn-km-unit">km</span>
                                    </div>
                                </div>
                                <div className="nn-field">
                                    <label className="nn-fl" style={{ color: "#7c3aed" }}>Indemnité calculée</label>
                                    <div className="nn-km-result">
                                        <div>
                                            <div className="nn-km-result-label">Tranche {tranche || "—"} · {cv} CV</div>
                                            <div className="nn-km-result-detail">{kmNum > 0 ? `${kmNum} km × ${rateLabel}` : "Saisir un kilométrage"}</div>
                                        </div>
                                        <div className="nn-km-result-value">{ind > 0 ? fmt(ind) : "—"}</div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    )}

                    {/* ── TVA EXCEL ── */}
                    {!isKm && isExcel && (
                        <TvaExcelTable
                            tvaItems={tvaItems}
                            onUpdate={items => set("tvaItems", items)}
                        />
                    )}

                    {/* ── NUITS (Hébergement) ── */}
                    {depense.categorie.toLowerCase().includes("hebergement") && (
                        <div className="nn-nuits-box">
                            <div>
                                <div className="nn-nuits-label">🌙 Nombre de nuits</div>
                                {ttcTotal > 0 && (parseInt(depense.nuits) || 0) > 0 && (
                                    <div style={{ fontSize: 10, color: "#6366f1", marginTop: 2 }}>
                                        Soit <span className="nn-nuits-par-nuit">
                                            {fmt(ttcTotal / (parseInt(depense.nuits) || 1))}
                                        </span> / nuit
                                    </div>
                                )}
                            </div>
                            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                                <button type="button" className="nn-tva-btn rm"
                                    disabled={(parseInt(depense.nuits) || 0) <= 1}
                                    onClick={() => set("nuits", String(Math.max(1, (parseInt(depense.nuits) || 1) - 1)))}>
                                    −
                                </button>
                                <input
                                    type="number" min="1" className="nn-input"
                                    style={{ maxWidth: 64, textAlign: "center", borderColor: "rgba(99,102,241,.35)" }}
                                    value={depense.nuits}
                                    onChange={e => set("nuits", e.target.value)}
                                    placeholder="1"
                                />
                                <button type="button" className="nn-tva-btn add"
                                    onClick={() => set("nuits", String((parseInt(depense.nuits) || 0) + 1))}>
                                    +
                                </button>
                                <span style={{ fontSize: 11, color: "#6b7280", fontWeight: 600, whiteSpace: "nowrap" }}>
                                    nuit{(parseInt(depense.nuits) || 0) > 1 ? "s" : ""}
                                </span>
                            </div>
                        </div>
                    )}

                    {/* ── TVA CLASSIQUE ── */}
                    {!isKm && !isExcel && (
                        <div className="nn-tva-box">
                            <div className="nn-tva-head">
                                <span className="nn-tva-title">Montants &amp; TVA</span>
                                <span style={{ fontSize: 10, color: "var(--text-secondary, #9ca3af)", fontStyle: "italic" }}>
                                    Saisir le montant TTC — HT calculé automatiquement
                                </span>
                            </div>
                            <div className="nn-tva-row" style={{ marginBottom: 4 }}>
                                <div /><div />
                                {["Taux TVA", "Montant TTC", "HT calculé", "TVA"].map((h, i) => (
                                    <div key={i} style={{ fontSize: 9, fontWeight: 700, textTransform: "uppercase", color: "var(--text-secondary, #9ca3af)", letterSpacing: ".04em" }}>{h}</div>
                                ))}
                            </div>
                            {tvaItems.map((item, idx) => {
                                const ttc = parseFloat(item.montantTTC) || 0;
                                const taux = parseFloat(item.taux) || 0;
                                const ht = ttcToHt(ttc, taux);
                                const tva = ttcToTva(ttc, taux);
                                return (
                                    <div key={idx} className="nn-tva-row">
                                        <button type="button" className="nn-tva-btn add" onClick={() => addTvaAfter(idx)} title="Ajouter une ligne après">+</button>
                                        <button type="button" className="nn-tva-btn rm" disabled={tvaItems.length <= 1} onClick={() => removeTva(idx)} title="Supprimer cette ligne">−</button>
                                        <select className="nn-input" style={{ fontSize: 12, padding: "6px 8px" }}
                                            value={item.taux} onChange={e => updTva(idx, "taux", e.target.value)}>
                                            <option value="">— Taux —</option>
                                            {TAUX_TVA.map((t, i) => (
                                                <option key={i} value={String(t.taux)}>{t.libelle}</option>
                                            ))}
                                        </select>
                                        <div style={{ position: "relative" }}>
                                            <input type="number" min="0" step="0.01" className="nn-input"
                                                style={{ fontSize: 12, padding: "6px 22px 6px 8px" }}
                                                value={item.montantTTC}
                                                onChange={e => updTva(idx, "montantTTC", e.target.value)}
                                                placeholder="0,00" />
                                            <span style={{ position: "absolute", right: 7, top: "50%", transform: "translateY(-50%)", fontSize: 11, color: "#9ca3af", pointerEvents: "none" }}>€</span>
                                        </div>
                                        <div className={`nn-tva-computed ttc${ttc <= 0 ? " na" : ""}`}>{ttc > 0 ? fmt(ht) : "—"}</div>
                                        <div className={`nn-tva-computed tva${tva <= 0 ? " na" : ""}`}>{tva > 0 ? fmt(tva) : taux === 0 && ttc > 0 ? "0 €" : "—"}</div>
                                    </div>
                                );
                            })}
                            {tvaItems.length > 1 && ttcTotal > 0 && (
                                <div className="nn-tva-total">
                                    <div className="nn-tva-total-cell">
                                        <div className="nn-tva-total-lbl">HT</div>
                                        <div className="nn-tva-total-val" style={{ color: "#7c3aed" }}>{fmt(htTotal)}</div>
                                    </div>
                                    <div className="nn-tva-total-cell">
                                        <div className="nn-tva-total-lbl">TVA</div>
                                        <div className="nn-tva-total-val" style={{ color: "#4f46e5" }}>{fmt(tvaTotal)}</div>
                                    </div>
                                    <div className="nn-tva-total-cell">
                                        <div className="nn-tva-total-lbl">TTC</div>
                                        <div className="nn-tva-total-val">{fmt(ttcTotal)}</div>
                                    </div>
                                </div>
                            )}
                        </div>
                    )}

                    {/* ── REPAS — participants + alertes ── */}
           {isRepas && (
                        <div className="nn-repas-box">
                            <div className="nn-repas-title">🍽️ Participants</div>

                            <div className="nn-repas-info">
                                <span className="nn-repas-info-icon">ℹ️</span>
                                <span>
                                    Un repas professionnel <strong>ne doit pas dépasser 25 € par personne</strong> (sauf repas événementiel).
                                </span>
                            </div>

                            {/* ── Choix seul ou accompagné ── */}
                            <div className="nn-field" style={{ marginBottom: 12 }}>
                                <label className="nn-fl" style={{ color: "#92400e" }}>Type de repas <span>*</span></label>
                                <div style={{ display: "flex", gap: 8 }}>
                                    <button
                                        type="button"
                                        onClick={() => handleNombreParticipants("0")}
                                        style={{
                                            flex: 1, padding: "10px 14px", borderRadius: 8, cursor: "pointer",
                                            fontFamily: "inherit", fontSize: 12, fontWeight: 700,
                                            border: (parseInt(depense.nombreParticipants) === 0 && depense.nombreParticipants !== "")
                                                ? "2px solid #d97706"
                                                : "1.5px solid rgba(0,0,0,.12)",
                                            background: (parseInt(depense.nombreParticipants) === 0 && depense.nombreParticipants !== "")
                                                ? "rgba(251,191,36,.18)"
                                                : "rgba(0,0,0,.02)",
                                            color: (parseInt(depense.nombreParticipants) === 0 && depense.nombreParticipants !== "")
                                                ? "#92400e"
                                                : "var(--text-secondary, #6b7280)",
                                            transition: "all .15s",
                                        }}>
                                        🧑 Repas seul
                                    </button>
                                    <button
                                        type="button"
                                        onClick={() => {
                                            // Si on clique "accompagné" et qu'on était à 0 ou vide, mettre à 1
                                            const current = parseInt(depense.nombreParticipants) || 0;
                                            if (current === 0 || depense.nombreParticipants === "") {
                                                handleNombreParticipants("1");
                                            }
                                        }}
                                        style={{
                                            flex: 1, padding: "10px 14px", borderRadius: 8, cursor: "pointer",
                                            fontFamily: "inherit", fontSize: 12, fontWeight: 700,
                                            border: (parseInt(depense.nombreParticipants) > 0)
                                                ? "2px solid #d97706"
                                                : "1.5px solid rgba(0,0,0,.12)",
                                            background: (parseInt(depense.nombreParticipants) > 0)
                                                ? "rgba(251,191,36,.18)"
                                                : "rgba(0,0,0,.02)",
                                            color: (parseInt(depense.nombreParticipants) > 0)
                                                ? "#92400e"
                                                : "var(--text-secondary, #6b7280)",
                                            transition: "all .15s",
                                        }}>
                                        👥 Accompagné
                                    </button>
                                </div>
                            </div>

                            {/* ── Si accompagné : sélecteur nombre + champs ── */}
                            {depense.nombreParticipants !== "" && parseInt(depense.nombreParticipants) > 0 && (
                                <>
                                    <div className="nn-field" style={{ marginBottom: 10 }}>
                                        <label className="nn-fl" style={{ color: "#92400e" }}>
                                            Nombre de convives invités{" "}
                                            <span style={{ color: "#92400e", fontWeight: 400, textTransform: "none", fontSize: 9 }}>
                                                (vous êtes toujours compté dans le total)
                                            </span>
                                        </label>
                                        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                                            <button type="button" className="nn-p-btn rm"
                                                disabled={(parseInt(depense.nombreParticipants) || 0) <= 1}
                                                onClick={() => handleNombreParticipants(String(Math.max(1, (parseInt(depense.nombreParticipants) || 1) - 1)))}
                                            >−</button>

                                            <input type="number" min="1" className="nn-input"
                                                style={{ borderColor: repasAlerte ? "rgba(245,158,11,.5)" : "rgba(251,191,36,.4)", maxWidth: 80, textAlign: "center" }}
                                                value={depense.nombreParticipants}
                                                onChange={e => {
                                                    const v = Math.max(1, parseInt(e.target.value) || 1);
                                                    handleNombreParticipants(String(v));
                                                }}
                                                placeholder="1"
                                            />

                                            <button type="button" className="nn-p-btn add"
                                                onClick={() => handleNombreParticipants(String((parseInt(depense.nombreParticipants) || 1) + 1))}
                                            >+</button>

                                            <span style={{ fontSize: 11, color: repasAlerte ? "#b45309" : "#92400e", fontWeight: 700 }}>
                                                {nbPersonnes} convive{nbPersonnes > 1 ? "s" : ""} au total
                                                {ttcTotal > 0 && ` · ${new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR" }).format(ttcParPersonne)}/pers.`}
                                            </span>
                                        </div>
                                    </div>

                                    {/* Alertes */}
                                    {repasAlerte && (
                                        <div className="nn-repas-info warn" style={{ marginBottom: 8 }}>
                                            <span className="nn-repas-info-icon">⚠️</span>
                                            <span>
                                                <strong>Attention :</strong> ce repas revient à{" "}
                                                <strong>{new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR" }).format(ttcParPersonne)}</strong>{" "}
                                                par personne, au-delà du plafond de 25 €.
                                                La soumission reste possible — mentionnez le contexte dans le commentaire.
                                            </span>
                                        </div>
                                    )}
                                    {isEvenementiel && ttcParPersonne > 25 && (
                                        <div className="nn-repas-info" style={{ background: "rgba(99,102,241,.07)", borderColor: "rgba(99,102,241,.35)", color: "#4338ca", marginBottom: 8 }}>
                                            <span className="nn-repas-info-icon">🎉</span>
                                            <span>Repas <strong>événementiel</strong> détecté — le plafond de 25 €/personne ne s'applique pas.</span>
                                        </div>
                                    )}

                                    {/* Champs participants */}
                                    <div>
                                        <div className="nn-participant-row" style={{ marginBottom: 4 }}>
                                            <span style={{ fontSize: 9, fontWeight: 700, textTransform: "uppercase", color: "#92400e", letterSpacing: ".04em" }}>Nom *</span>
                                            <span style={{ fontSize: 9, fontWeight: 700, textTransform: "uppercase", color: "#92400e", letterSpacing: ".04em" }}>Prénom *</span>
                                            <span style={{ fontSize: 9, fontWeight: 700, textTransform: "uppercase", color: "#92400e", letterSpacing: ".04em" }}>Société</span>
                                            <div /><div />
                                        </div>
                                        {depense.participants.map((p, i) => (
                                            <div key={i} className="nn-participant-row">
                                                <input className="nn-input"
                                                    style={{ fontSize: 12, borderColor: !p.nom?.trim() ? 'rgba(239,68,68,.5)' : undefined }}
                                                    value={p.nom} onChange={e => updP(i, "nom", e.target.value)}
                                                    placeholder={`Nom ${i + 1} *`} />
                                                <input className="nn-input"
                                                    style={{ fontSize: 12, borderColor: !p.prenom?.trim() ? 'rgba(239,68,68,.5)' : undefined }}
                                                    value={p.prenom} onChange={e => updP(i, "prenom", e.target.value)}
                                                    placeholder="Prénom *" />
                                                <input className="nn-input" style={{ fontSize: 12 }}
                                                    value={p.societe || ""} onChange={e => updP(i, "societe", e.target.value)}
                                                    placeholder="Société" />
                                                <button type="button" className="nn-p-btn add"
                                                    onClick={() => {
                                                        const newList = [...depense.participants.slice(0, i + 1), { nom: "", prenom: "", societe: "" }, ...depense.participants.slice(i + 1)];
                                                        set("participants", newList);
                                                        set("nombreParticipants", String(newList.length));
                                                    }}>+</button>
                                                <button type="button" className="nn-p-btn rm"
                                                    onClick={() => {
                                                        const newList = depense.participants.filter((_, j) => j !== i);
                                                        if (newList.length === 0) {
                                                            handleNombreParticipants("0");
                                                        } else {
                                                            set("participants", newList);
                                                            set("nombreParticipants", String(newList.length));
                                                        }
                                                    }}>−</button>
                                            </div>
                                        ))}
                                    </div>
                                </>
                            )}

                            {/* ── Si repas seul : badge confirmation ── */}
                     

                            {/* ── Aucun choix encore ── */}
                            {depense.nombreParticipants === "" && (
                                <div style={{ fontSize: 11, color: "#92400e", fontWeight: 600, opacity: 0.7, textAlign: "center", padding: "4px 0" }}>
                                    ↑ Choisissez si vous étiez seul ou accompagné
                                </div>
                            )}
                        </div>
                    )}

                    {/* ── JUSTIFICATIF ── */}
                    <div className="nn-file-area">
                        <label className="nn-fl">
                            Justificatif{isKm ? " (facultatif)" : " *"}
                            {totalFiles > 0 && <span style={{ marginLeft: 6, background: "#eef2ff", color: "#6366f1", padding: "1px 6px", borderRadius: 8, fontSize: 9, fontWeight: 700 }}>{totalFiles}</span>}
                        </label>
                        <div className={`nn-drop${depense.files.length > 0 ? " ok" : ""}`}
                            onClick={() => fileRef.current?.click()}
                            onDragOver={e => e.preventDefault()}
                            onDrop={e => { e.preventDefault(); addFiles(e.dataTransfer.files); }}>
                            {depense.files.length > 0
                                ? `✓ ${depense.files.length} fichier(s) — glisser pour en ajouter`
                                : "Glisser un fichier ou cliquer — PDF, JPG, PNG"}
                            <input ref={fileRef} type="file" multiple accept=".pdf,.jpg,.jpeg,.png"
                                onChange={e => addFiles(e.target.files)} style={{ display: "none" }} />
                        </div>

                        <FileGrid
                            files={depense.files}
                            ghostMetas={ghostMetas}
                            apiBaseUrl={apiBaseUrl}
                            qrFiles={depense.qrFiles ?? []}
                            onRemoveFile={i => {
                                const upd = depense.files.filter((_, j) => j !== i);
                                const updM = [...(depense.filesMeta ?? []).slice(0, ghostCount), ...(depense.filesMeta ?? []).slice(ghostCount).filter((_, j) => j !== i)];
                                setStoredFiles(depense.id, upd); set("files", upd); set("filesMeta", updM);
                            }}
                            onRemoveMeta={i => set("filesMeta", (depense.filesMeta ?? []).filter((_, j) => j !== i))}
                            onRemoveQr={i => set("qrFiles", (depense.qrFiles ?? []).filter((_, j) => j !== i))}
                        />

                        {isKm && totalFiles === 0 && !depense.qrUploaded && (
                            <div style={{ marginTop: 6, background: "rgba(124,58,237,.05)", border: "1px solid rgba(124,58,237,.18)", borderRadius: 6, padding: "5px 9px", fontSize: 11, color: "#7c3aed", fontWeight: 600 }}>
                                Déplacement kilométrique — justificatif facultatif
                            </div>
                        )}

                        {!hasRealQrFile && onGenerateQR && (
                            <>
                                <button type="button" className="nn-qr-btn" onClick={() => onGenerateQR(depense.id)}>
                                    📱 Joindre via mobile (QR Code)
                                </button>
                                {depense.qrLink && (
                                    <div className="nn-qr-box">
                                        <QRCode value={depense.qrLink} size={130} />
                                        <span style={{ fontSize: 11, color: "#7c3aed", fontWeight: 600, textAlign: "center" }}>
                                            📲 Scannez pour joindre depuis votre mobile
                                        </span>
                                    </div>
                                )}
                            </>
                        )}

                        {hasRealQrFile && (
                            <div className="nn-qr-uploaded">
                                <span>✅</span>
                                <div style={{ fontSize: 12, fontWeight: 700, color: "#15803d" }}>Justificatif reçu via mobile</div>
                            </div>
                        )}
                    </div>

                    <button className="nn-btn-del-card" onClick={() => onDelete(depense.id)}>
                        − Supprimer cette dépense
                    </button>
                </div>
            )}
        </div>
    );
});

// ── COMPOSANT PRINCIPAL ───────────────────────────────
export default function NouvelleNote({
    onSubmit, apiBaseUrl, authToken,
    initialBrouillonId = null,
    libelleInitial = '', dateDebutInitiale = '', commentaireInitial = '',
    depensesInitiales,
    onNavigateToProfil,
}: NouvelleNoteProps) {
    
    const initDepenses = (defaultCv = 7): Depense[] => {
        if (depensesInitiales && depensesInitiales.length > 0) {
            return depensesInitiales.map((l: any) => {
                const d = newDepense(defaultCv);
                const tvaItems: TvaItem[] = l.tvaItems?.length
                    ? l.tvaItems.map(normalizeTvaItem)
                    : [{ taux: l.tauxTVA ? String(l.tauxTVA) : "20", montantTTC: l.montant ? String(l.montant) : "" }];

                return {
                    ...d, ...l, id: Math.random(), files: [],
                    filesMeta: l.filesMeta ?? [], qrFiles: l.qrFiles ?? [],
                    qrLink: null, qrUploaded: l.qrNoteRef ? true : false,
                    tvaItems,
                    km: l.km ? String(l.km) : "",
                    chevaux: l.chevaux ? parseInt(String(l.chevaux)) : defaultCv,
                    participants: l.participants?.length ? l.participants : [{ nom: "", prenom: "", societe: "" }],
                    nombreParticipants: l.nombreParticipants ? String(l.nombreParticipants) : "",
                    description: l.description || "",
                };
            });
        }
        return [newDepense(defaultCv)];
    };

    const [titre, setTitre] = useState(libelleInitial || "");
    const [dateDebut, setDateDebut] = useState(dateDebutInitiale || "");
    const [dateFin, setDateFin] = useState("");
    const [commentaire, setComment] = useState(commentaireInitial || "");
    const [depenses, setDepenses] = useState<Depense[]>(() => initDepenses(7));
    const [profilVehicule, setProfilVehicule] = useState<ProfilVehiculeData | null>(null);
    const [expandedId, setExpandedId] = useState<number | null>(() => {
        const init = initDepenses(); return init.length > 0 ? init[0].id : null;
    });
    const [selectedBrouillonIds, setSelectedBrouillonIds] = useState<Set<number>>(new Set());
    const [deletingAll, setDeletingAll] = useState(false);

    const [brouillons, setBrouillons] = useState<BrouillonServeur[]>([]);
    const [activeBrouillonId, setActiveBrouillonId] = useState<number | null>(initialBrouillonId);
    const [showBrouillonList, setShowBrouillonList] = useState(false);
    const [loadingBrouillons, setLoadingBrouillons] = useState(false);
    const [saveStatus, setSaveStatus] = useState<"idle" | "saving" | "saved" | "error">("idle");
    const [submitError, setSubmitError] = useState("");
    const [submitting, setSubmitting] = useState(false);

    const qrPollingRefs = useRef<Record<number, ReturnType<typeof setInterval>>>({});
    const saveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
    const isFirstRender = useRef(true);
    const activeBrouillonIdRef = useRef<number | null>(initialBrouillonId);

    useEffect(() => {
        if (!authToken) return;
        fetch(`${apiBaseUrl}/api/profil/vehicule`, {
            headers: { Authorization: `Bearer ${authToken}` }
        })
            .then(r => r.ok ? r.json() : null)
            .then(data => {
                if (data?.configured && data.vehicule) {
                    setProfilVehicule(data.vehicule);
                    setDepenses(prev => prev.map(d => ({
                        ...d,
                        chevaux: (d.categorie || "").toLowerCase().includes("kilom")
                            ? data.vehicule.chevaux
                            : d.chevaux
                    })));
                }
            })
            .catch(() => { });
    }, [authToken, apiBaseUrl]);

    useEffect(() => { if (depenses.length > 0 && expandedId === null) setExpandedId(depenses[0].id); }, []);
    useEffect(() => { activeBrouillonIdRef.current = activeBrouillonId; }, [activeBrouillonId]);
    useEffect(() => { return () => { Object.values(qrPollingRefs.current).forEach(clearInterval); }; }, []);

    const getHeaders = useCallback(() => ({ "Authorization": `Bearer ${authToken}`, "Content-Type": "application/json" }), [authToken]);
    const handleToggle = useCallback((id: number) => setExpandedId(prev => prev === id ? null : id), []);
    const handleUpdateDepense = useCallback((id: number, f: keyof Depense, v: any) =>
        setDepenses(p => p.map(d => d.id === id ? { ...d, [f]: v } : d)), []);
    const handleDeleteDepense = useCallback((id: number) => { filesStore.delete(id); setDepenses(p => p.filter(d => d.id !== id)); }, []);
    const handleAddDepense = useCallback(() => {
        const d = newDepense(); setDepenses(p => [...p, d]); setExpandedId(d.id);
    }, []);

    const generateQRForDepense = useCallback(async (depenseId: number) => {
        const tempRef = `NDF-DEP-${depenseId}-${Date.now()}`;
        try {
            const res = await fetch(`${apiBaseUrl}/api/upload/generate-link`, { method: "POST", headers: getHeaders(), body: JSON.stringify({ noteRef: tempRef }) });
            const data = await res.json();
            if (!res.ok) { alert("Erreur génération QR"); return; }
            setDepenses(prev => prev.map(d => d.id === depenseId ? { ...d, qrLink: data.uploadLink, qrNoteRef: tempRef, qrUploaded: false } : d));
            if (qrPollingRefs.current[depenseId]) clearInterval(qrPollingRefs.current[depenseId]);
            qrPollingRefs.current[depenseId] = setInterval(async () => {
                try {
                    const r = await fetch(`${apiBaseUrl}/api/upload/status/${tempRef}`, { headers: getHeaders() });
                    const s = await r.json();
                    if (s.uploaded) {
                        clearInterval(qrPollingRefs.current[depenseId]);
                        setDepenses(prev => prev.map(d => d.id === depenseId
                            ? {
                                ...d, qrUploaded: true, qrLink: null,
                                qrFiles: [
                                    ...(d.qrFiles ?? []),
                                    ...(Array.isArray(s.files) ? s.files.map((f: any) => ({ ...f, origin: 'qr' as const })) : [])
                                ]
                            }
                            : d));
                    }
                } catch { }
            }, 3000);
        } catch { }
    }, [apiBaseUrl, getHeaders]);



    const handleDeleteSelected = async () => {
                                        const ids = Array.from(selectedBrouillonIds);
                                        if (ids.length === 0) return;
                                        if (!window.confirm(`Supprimer ${ids.length} brouillon(s) ?`)) return;
                                        setDeletingAll(true);
                                        try {
                                            await Promise.all(ids.map(id =>
                                                fetch(`${apiBaseUrl}/api/notes/brouillons/${id}`, {
                                                    method: "DELETE",
                                                    headers: { Authorization: `Bearer ${authToken}` }
                                                })
                                            ));
                                            if (activeBrouillonIdRef.current && ids.includes(activeBrouillonIdRef.current)) {
                                                const d = newDepense();
                                                setTitre(""); setDateDebut(""); setDateFin(""); setComment("");
                                                setDepenses([d]); setExpandedId(d.id);
                                                activeBrouillonIdRef.current = null;
                                                setActiveBrouillonId(null);
                                                isFirstRender.current = true;
                                            }
                                            setSelectedBrouillonIds(new Set());
                                            await fetchBrouillons();
                                        } catch { }
                                        setDeletingAll(false);
                                    };

                                    const handleDeleteAll = async () => {
                                        if (brouillons.length === 0) return;
                                        if (!window.confirm(`Supprimer tous les ${brouillons.length} brouillons ?`)) return;
                                        setDeletingAll(true);
                                        try {
                                            await Promise.all(brouillons.map(b =>
                                                fetch(`${apiBaseUrl}/api/notes/brouillons/${b.id}`, {
                                                    method: "DELETE",
                                                    headers: { Authorization: `Bearer ${authToken}` }
                                                })
                                            ));
                                            const d = newDepense();
                                            setTitre(""); setDateDebut(""); setDateFin(""); setComment("");
                                            setDepenses([d]); setExpandedId(d.id);
                                            activeBrouillonIdRef.current = null;
                                            setActiveBrouillonId(null);
                                            setShowBrouillonList(false);
                                            isFirstRender.current = true;
                                            setSelectedBrouillonIds(new Set());
                                            await fetchBrouillons();
                                        } catch { }
                                        setDeletingAll(false);
                                    };


   
     const fetchBrouillons = useCallback(async () => {
         setLoadingBrouillons(true);
         try { const res = await fetch(`${apiBaseUrl}/api/notes/brouillons`, { headers: getHeaders() }); if (res.ok) setBrouillons(await res.json()); } catch { }
         setLoadingBrouillons(false);
     }, [apiBaseUrl, getHeaders]);
    useEffect(() => { fetchBrouillons(); }, [fetchBrouillons]);

    useEffect(() => {
        if (depensesInitiales && depensesInitiales.length > 0) return;
        if (!initialBrouillonId || !brouillons.length) return;
        const b = brouillons.find(b => b.id === initialBrouillonId);
        if (b) loadBrouillon(b);
    }, [initialBrouillonId, brouillons]);

    const scheduleSave = useCallback((state: any) => {
        if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
        setSaveStatus("saving");
        saveTimerRef.current = setTimeout(async () => {
            const currentId = activeBrouillonIdRef.current;
            const fd = new FormData();
            fd.append("libelle", state.titre || "Sans titre");
            fd.append("date", state.dateDebut || new Date().toISOString().split("T")[0]);
            fd.append("description", state.commentaire || "");
            fd.append("lignes", JSON.stringify(serializeDepenses(state.depenses)));
            for (const dep of state.depenses) {
                for (const file of getStoredFiles(dep.id)) fd.append(`files_${dep.id}`, file);
            }
            const headers = { Authorization: `Bearer ${authToken}` };
            try {
                if (currentId) {
                    const res = await fetch(`${apiBaseUrl}/api/notes/brouillons/${currentId}`, { method: "PUT", headers, body: fd });
                    if (res.ok) {
                        const data = await res.json();
                        if (data.uploadedFiles) {
                            setDepenses(prev => prev.map(d => {
                                const uploaded = data.uploadedFiles[d.id];
                                if (!uploaded?.length) return d;
                                const newQrFiles = [
                                    ...(d.qrFiles ?? []),
                                    ...uploaded.map((f: any) => ({ ...f, origin: 'upload' as const }))
                                ].filter((f, i, arr) => arr.findIndex(x => x.uploadUrl === f.uploadUrl) === i);
                                return { ...d, qrFiles: newQrFiles };
                            }));
                        }
                    }
                } else {
                    const res = await fetch(`${apiBaseUrl}/api/notes/brouillons`, { method: "POST", headers, body: fd });
                    const created = await res.json();
                    activeBrouillonIdRef.current = created.id;
                    setActiveBrouillonId(created.id);
                }
                await fetchBrouillons();
                setSaveStatus("saved");
                state.depenses.forEach((d: Depense) => setStoredFiles(d.id, []));
            } catch { setSaveStatus("error"); }
        }, 1500);
    }, [apiBaseUrl, authToken, fetchBrouillons]);

    useEffect(() => {
        if (isFirstRender.current) { isFirstRender.current = false; return; }
        scheduleSave({ titre, dateDebut, dateFin, commentaire, depenses });
    }, [titre, dateDebut, dateFin, commentaire, depenses, scheduleSave]);

    const loadBrouillon = (b: BrouillonServeur) => {
        setTitre(b.libelle || ""); setComment(b.description || "");
        setDateDebut(b.date ? b.date.split("T")[0] : "");
        try {
            const lignes = JSON.parse(b.lignesJson || "[]");
            const parsed = lignes.map((l: any): Depense => {
                const tvaItems: TvaItem[] = (l.tvaItems?.length
                    ? l.tvaItems.map(normalizeTvaItem)
                    : [{ taux: "20", montantTTC: "" }]
                );
                const hasRealQr = (l.qrFiles ?? []).some((f: any) => !f.origin || f.origin === 'qr');
                return {
                    ...newDepense(), ...l, files: [],
                    filesMeta: l.filesMeta ?? [], qrFiles: l.qrFiles ?? [],
                    qrLink: null,
                    qrUploaded: hasRealQr,
                    tvaItems,
                    participants: l.participants?.length ? l.participants : [],
                    nombreParticipants: l.nombreParticipants ? String(l.nombreParticipants) : "",
                };
            });
            setDepenses(parsed); setExpandedId(parsed[0]?.id ?? null);
        } catch { setDepenses([newDepense()]); }
        activeBrouillonIdRef.current = b.id; setActiveBrouillonId(b.id);
        setShowBrouillonList(false); isFirstRender.current = true;
    };

    const handleNewBrouillon = () => {
        const d = newDepense();
        setTitre(""); setDateDebut(""); setDateFin(""); setComment(""); setDepenses([d]); setExpandedId(d.id);
        activeBrouillonIdRef.current = null; setActiveBrouillonId(null);
        setShowBrouillonList(false); isFirstRender.current = true;
    };

    const handleDeleteBrouillon = async (id: number) => {
        if (!window.confirm("Supprimer ce brouillon ?")) return;
        try {
            await fetch(`${apiBaseUrl}/api/notes/brouillons/${id}`, { method: "DELETE", headers: getHeaders() });
            if (id === activeBrouillonIdRef.current) handleNewBrouillon();
            fetchBrouillons();
        } catch { }
    };

    const handleSubmit = async () => {
        setSubmitError("");
        if (submitting) return;
        if (!titre.trim()) { setSubmitError("Veuillez saisir un titre."); return; }
        if (dateDebut && isDateFutureMonth(dateDebut)) {
                                        setSubmitError("La date de la note ne peut pas être dans un mois futur. Vous ne pouvez créer des notes que pour le mois en cours ou des mois passés.");
                                        return;
                                    }
        for (const d of depenses) {
            if (!d.date || !d.libelle.trim()) {
                setSubmitError(`La dépense "${d.libelle || "sans libellé"}" doit avoir une date et un libellé.`);
                setExpandedId(d.id); return;
            }
                                    // ✅ Bloquer les dates dans un mois futur
                                    if (isDateFutureMonth(d.date)) {
                                        setSubmitError(`"${d.libelle}" — la date ne peut pas être dans un mois futur. Vous ne pouvez soumettre des frais que pour le mois en cours ou des mois passés.`);
                                        setExpandedId(d.id); return;
                                    }
            const isKmLine = d.categorie.toLowerCase().includes("kilom");
            if (isKmLine && (!d.km || parseFloat(d.km) <= 0)) {
                setSubmitError(`"${d.libelle}" doit avoir un kilométrage.`);
                setExpandedId(d.id); return;
            }
            if (!isKmLine) {
                const hasFiles = d.files.length > 0 || (d.filesMeta ?? []).length > 0 || (d.qrFiles ?? []).length > 0;
                if (!hasFiles) {
                    setSubmitError(`"${d.libelle}" — un justificatif est obligatoire pour cette catégorie.`);
                    setExpandedId(d.id); return;
                }
            }
            if (d.categorie.toLowerCase().includes("repas")) {
                for (let pi = 0; pi < d.participants.length; pi++) {
                    const p = d.participants[pi];
                    if (!p.nom?.trim() || !p.prenom?.trim()) {
                        setSubmitError(`"${d.libelle}" — le nom et prénom du participant ${pi + 1} sont obligatoires.`);
                        setExpandedId(d.id); return;
                    }
                }
                // Pas de blocage sur le dépassement 25€ — c'est un warning uniquement
            }
        }
        setSubmitting(true);
        try {
            const depensesBackend = depenses.map(d => ({
                ...d,
                files: getStoredFiles(d.id).length > 0 ? getStoredFiles(d.id) : d.files,
                tvaItems: d.tvaItems.map(tvaItemToBackend),
                qrFiles: d.qrFiles ?? [],
            }));
            await onSubmit(titre, dateDebut, dateFin, commentaire, depensesBackend);
        } catch (e: any) { setSubmitError(e.message || "Erreur lors de la soumission"); setSubmitting(false); }
    };

    // ✅ Calcul des totaux globaux — gestion du cas MIXED
    const { totalTTC, totalHT, totalTVA } = useMemo(() => {
        let ttc = 0, ht = 0;
        depenses.forEach(d => {
            const isKm = d.categorie.toLowerCase().includes("kilom");
            if (isKm) {
                const ind = calcIndemnite(parseFloat(d.km) || 0, d.chevaux);
                ttc += ind; ht += ind;
            } else {
                d.tvaItems.forEach(item => {
                    const ttcVal = parseFloat(item.montantTTC) || 0;
                    if (ttcVal <= 0) return;
                    ttc += ttcVal;
                    ht += itemToHt(item);
                });
            }
        });
        return { totalTTC: ttc, totalHT: ht, totalTVA: ttc - ht };
    }, [depenses]);

    const activeBrouillon = brouillons.find(b => b.id === activeBrouillonId);
    const SaveIndicator = () => {
        if (saveStatus === "saving") return <span className="nn-save saving">💾 Sauvegarde…</span>;
        if (saveStatus === "saved") return <span className="nn-save saved">✓ Sauvegardé</span>;
        if (saveStatus === "error") return <span className="nn-save error">⚠ Erreur</span>;
        return null;
    };

    return (
        <>
            <style>{css}</style>
            <div className="nn">
                <div className="nn-layout">
                    <div className="nn-main">

                        {activeBrouillon && (
                            <div className="nn-active-bro">
                                <div>
                                    <div className="nn-active-bro-name">💾 {activeBrouillon.libelle || "Sans titre"}</div>
                                    <div className="nn-active-bro-date">Sauvegardé le {new Date(activeBrouillon.DateModification).toLocaleString("fr-FR", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" })}</div>
                                </div>
                                <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
                                    <SaveIndicator />
                                    <button className="nn-btn-sm red" onClick={() => handleDeleteBrouillon(activeBrouillon.id)}>🗑 Supprimer</button>
                                </div>
                            </div>
                        )}

                        {libelleInitial && !activeBrouillon && (
                            <div style={{ background: "linear-gradient(90deg, #fef2f2, #fff1f1)", border: "1.5px solid #fecaca", borderLeft: "4px solid #ef4444", borderRadius: "0 10px 10px 0", padding: "10px 16px", display: "flex", alignItems: "center", gap: 10 }}>
                                <span style={{ fontSize: 18, flexShrink: 0 }}>✏️</span>
                                <div>
                                    <div style={{ fontSize: 13, fontWeight: 700, color: "#dc2626" }}>Correction d'une note refusée</div>
                                    <div style={{ fontSize: 11, color: "#ef4444", marginTop: 2 }}>Les données ont été pré-remplies — corrigez puis resoumettez.</div>
                                </div>
                            </div>
                        )}

                  <div className="nn-bro-bar">
                            <div className="nn-bro-head">
                                <span style={{ display: "flex", alignItems: "center", gap: 8 }}>
                                    {loadingBrouillons ? "Chargement…" : `${brouillons.length} brouillon(s)`}
                                    {!activeBrouillon && <SaveIndicator />}
                                </span>
                                <div style={{ display: "flex", gap: 6, flexWrap: "wrap", alignItems: "center" }}>
                                    {/* Supprimer la sélection — visible si liste ouverte et items sélectionnés */}
                                    {showBrouillonList && selectedBrouillonIds.size > 0 && (
                                        <button className="nn-btn-sm red" onClick={handleDeleteSelected} disabled={deletingAll}>
                                            {deletingAll ? "⏳" : "🗑"} Supprimer ({selectedBrouillonIds.size})
                                        </button>
                                    )}
                                    {/* Tout supprimer — visible si aucune sélection active */}
                                    {brouillons.length > 0 && selectedBrouillonIds.size === 0 && (
                                        <button className="nn-btn-sm red" onClick={handleDeleteAll} disabled={deletingAll} style={{ opacity: 0.75 }}>
                                            {deletingAll ? "⏳" : "🗑"} Tout supprimer
                                        </button>
                                    )}
                                    {brouillons.length > 0 && (
                                        <button className="nn-btn-sm indigo" onClick={() => {
                                            setShowBrouillonList(v => !v);
                                            if (showBrouillonList) setSelectedBrouillonIds(new Set());
                                        }}>
                                            {showBrouillonList ? "▲ Réduire" : "▼ Voir"}
                                        </button>
                                    )}
                                    <button className="nn-btn-sm green" onClick={handleNewBrouillon}>+ Nouvelle note</button>
                                </div>
                            </div>

                            {/* Ligne "Tout sélectionner" */}
                            {showBrouillonList && brouillons.length > 1 && (
                                <div style={{
                                    display: "flex", alignItems: "center", gap: 8,
                                    padding: "6px 14px", borderBottom: "1px solid rgba(0,0,0,.05)",
                                    background: "rgba(0,0,0,.015)",
                                }}>
                                    <input
                                        type="checkbox"
                                        checked={selectedBrouillonIds.size === brouillons.length && brouillons.length > 0}
                                        ref={el => {
                                            if (el) el.indeterminate =
                                                selectedBrouillonIds.size > 0 && selectedBrouillonIds.size < brouillons.length;
                                        }}
                                        onChange={e => setSelectedBrouillonIds(
                                            e.target.checked ? new Set(brouillons.map(b => b.id)) : new Set()
                                        )}
                                        style={{ width: 14, height: 14, cursor: "pointer" }}
                                    />
                                    <span style={{ fontSize: 10, fontWeight: 700, color: "var(--text-secondary, #6b7280)", textTransform: "uppercase", letterSpacing: ".04em" }}>
                                        Tout sélectionner
                                    </span>
                                    {selectedBrouillonIds.size > 0 && (
                                        <span style={{ fontSize: 10, color: "#6366f1", fontWeight: 600 }}>
                                            — {selectedBrouillonIds.size} sélectionné(s)
                                        </span>
                                    )}
                                </div>
                            )}

                            {/* Liste des brouillons */}
                            {showBrouillonList && brouillons.map(b => (
                                <div key={b.id} className={`nn-bro-row${b.id === activeBrouillonId ? " active" : ""}`}>
                                    <input
                                        type="checkbox"
                                        checked={selectedBrouillonIds.has(b.id)}
                                        onChange={e => {
                                            const next = new Set(selectedBrouillonIds);
                                            e.target.checked ? next.add(b.id) : next.delete(b.id);
                                            setSelectedBrouillonIds(next);
                                        }}
                                        onClick={e => e.stopPropagation()}
                                        style={{ width: 14, height: 14, cursor: "pointer", flexShrink: 0 }}
                                    />
                                    <div className="nn-bro-name" style={{ color: b.id === activeBrouillonId ? "#6366f1" : undefined }}>
                                        {b.libelle || "Sans titre"}
                                        {b.id === activeBrouillonId && <span className="nn-bro-active-tag">EN COURS</span>}
                                    </div>
                                    <span className="nn-bro-date">
                                        {new Date(b.DateModification).toLocaleDateString("fr-FR", { day: "2-digit", month: "short" })}
                                    </span>
                                    <div style={{ display: "flex", gap: 5 }}>
                                        {b.id !== activeBrouillonId && (
                                            <button className="nn-btn-sm indigo" onClick={() => loadBrouillon(b)}>Ouvrir</button>
                                        )}
                                        <button className="nn-btn-sm red" onClick={() => handleDeleteBrouillon(b.id)}>🗑</button>
                                    </div>
                                </div>
                            ))}
                        </div>

                        <div className="nn-topbar">
                            <div className="nn-topbar-left">
                                <span style={{ background: "rgba(200,147,58,.12)", color: "#c8933a", border: "1px solid rgba(200,147,58,.35)", borderRadius: 20, padding: "3px 10px", fontSize: 11, fontWeight: 700 }}>
                                    {submitting ? "⏳ Soumission…" : "Brouillon"}
                                </span>
                                <span style={{ fontSize: 11, color: "var(--text-secondary, #6b7280)", fontWeight: 500 }}>
                                    {depenses.length} dépense{depenses.length > 1 ? "s" : ""}
                                    {totalTTC > 0 && ` · ${fmt(totalTTC)}`}
                                </span>
                            </div>
                        </div>

                        {submitError && <div className="nn-error">⚠️ {submitError}</div>}

                        <div className="nn-meta">
                            <div className="nn-meta-field">
                                <label>Titre <span>*</span></label>
                                <input className="nn-input" value={titre} onChange={e => setTitre(e.target.value)} placeholder="Ex: Mission Lyon mars" disabled={submitting} />
                            </div>
                            <div className="nn-meta-field">
                                <label>Date <span>*</span></label>
                              <input 
                                    type="date" 
                                    className="nn-input" 
                                    value={dateDebut} 
                                    max={getMaxAllowedDate()}
                                    onChange={e => setDateDebut(e.target.value)} 
                                    disabled={submitting} 
                                />
                            </div>
                            <div className="nn-meta-field">
                                <label>Commentaire</label>
                                <input className="nn-input" value={commentaire} onChange={e => setComment(e.target.value)} placeholder="Contexte..." disabled={submitting} />
                            </div>
                        </div>

                        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }}>
                            <span style={{ fontSize: 10, fontWeight: 800, textTransform: "uppercase", letterSpacing: ".06em", color: "var(--text-secondary, #6b7280)" }}>
                                Dépenses ({depenses.length})
                            </span>
                            <button className="nn-btn-sm green" onClick={handleAddDepense} disabled={submitting} title="Ajouter une dépense">
                                + Ajouter
                            </button>
                        </div>

                 {depenses.map((d, i) => (
                     <DepenseCard key={d.id} depense={d} index={i} total={depenses.length}
                         expanded={expandedId === d.id}
                         onToggle={handleToggle} onUpdate={handleUpdateDepense}
                         onDelete={handleDeleteDepense} onGenerateQR={generateQRForDepense}
                         disabled={submitting} apiBaseUrl={apiBaseUrl} profilVehicule={profilVehicule}
                         onNavigateToProfil={onNavigateToProfil}
                         />
                 ))}

                        <button className="nn-btn-add-card" onClick={handleAddDepense} disabled={submitting}>
                            + Ajouter une dépense
                        </button>
                    </div>

                    {/* ── SIDEBAR RÉCAPITULATIF ── */}
                    <div className="nn-side">
                        <div className="nn-recap">
                            <div className="nn-recap-title">Récapitulatif</div>
                            {depenses.map(d => {
                                const isKm = d.categorie.toLowerCase().includes("kilom");
                                const amt = isKm
                                    ? calcIndemnite(parseFloat(d.km) || 0, d.chevaux)
                                    : d.tvaItems.reduce((s, item) => s + (parseFloat(item.montantTTC) || 0), 0);
                                return (
                                    <div className="nn-recap-item" key={d.id} onClick={() => setExpandedId(d.id)} style={{ cursor: "pointer" }}>
                                        <div className="nn-recap-dot" />
                                        <div style={{ flex: 1, minWidth: 0 }}>
                                            <div className="nn-recap-lbl">{d.libelle || "Sans libellé"}</div>
                                            <div className="nn-recap-cat">{CAT_ICONS[d.categorie]} {d.categorie}</div>
                                        </div>
                                        {amt > 0 && <span className="nn-recap-amt">{fmt(amt)}</span>}
                                    </div>
                                );
                            })}
                            <div className="nn-recap-totals">
                                <div className="nn-recap-row"><span>Total HT</span><span style={{ fontWeight: 700 }}>{totalHT > 0 ? fmt(totalHT) : "—"}</span></div>
                                <div className="nn-recap-row"><span>Total TVA</span><span style={{ fontWeight: 700 }}>{totalTVA > 0 ? fmt(totalTVA) : "—"}</span></div>
                                <div className="nn-recap-main"><span>Total TTC</span><span className="nn-recap-main-val">{totalTTC > 0 ? fmt(totalTTC) : "—"}</span></div>
                            </div>
                            <button className="nn-btn-recap-sub" onClick={handleSubmit} disabled={submitting}>
                                {submitting
                                    ? <span style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 8 }}><div className="nn-spinner" /> Soumission…</span>
                                    : "Soumettre la note ↗"}
                            </button>
                            <div className="nn-recap-subnote">{submitting ? "Envoi en cours..." : "Justificatifs vérifiés avant validation"}</div>
                        </div>
                    </div>
                </div>
            </div>
        </>
    );
} 