import { Controller } from '@hotwired/stimulus';
import { s3Sign, s3FormUpload, base64ToBlob, compressToJpegBase64 } from '../s3_upload.js';

/* Page /inventaires : changement de statut + export XLSX d'une session. */
export default class extends Controller {
    static targets = ['card', 'statusBadge', 'concessionPicker', 'mergeBar', 'mergeCount', 'vehicle', 'searchCount', 'searchEmpty'];

    // s3 = true → l'inventaire affiché est stocké sur S3 : le remplacement de photo passe par
    // un upload navigateur→S3 puis un re-OCR serveur (au lieu d'un envoi multipart au serveur).
    static values = { s3: { type: Boolean, default: false } };

    // Recherche dans un inventaire par immatriculation/VIN (casse, espaces, tirets ignorés).
    filterVehicles(event) {
        this._vehicleQuery = this.normalizeSearch(event.target.value);
        this.applyVehicleFilters();
    }

    // Filtre par erreur : '' (tous), 'with' (en erreur), 'without' (sans erreur).
    filterErrors(event) {
        this._vehicleError = event.target.value;
        this.applyVehicleFilters();
    }

    // Filtre par fiabilité du modèle : '' (tous), 'exact' (confiance ≥ 70 % ou corrigé à la main),
    // 'doute' (confiance < 70 % ou modèle non identifié).
    filterModel(event) {
        this._vehicleModel = event.target.value;
        this.applyVehicleFilters();
    }

    // Combine recherche texte + filtre erreur + filtre fiabilité du modèle sur les véhicules.
    applyVehicleFilters() {
        const q = this._vehicleQuery || '';
        const ef = this._vehicleError || '';
        const mf = this._vehicleModel || '';
        let shown = 0;
        this.vehicleTargets.forEach((li) => {
            const matchText = q === '' || this.normalizeSearch(li.dataset.search || '').includes(q);
            const inErr = li.dataset.error === '1';
            const matchErr = ef === '' || (ef === 'with' ? inErr : !inErr);
            const matchModel = mf === '' || (li.dataset.model || 'doute') === mf;
            const match = matchText && matchErr && matchModel;
            li.classList.toggle('hidden', !match);
            if (match) shown += 1;
        });
        const active = q !== '' || ef !== '' || mf !== '';
        if (this.hasSearchCountTarget) {
            this.searchCountTarget.textContent = active
                ? `${shown} véhicule${shown > 1 ? 's' : ''} sur ${this.vehicleTargets.length}`
                : '';
        }
        if (this.hasSearchEmptyTarget) {
            this.searchEmptyTarget.classList.toggle('hidden', !(active && shown === 0));
        }
    }

    normalizeSearch(s) {
        return String(s).toUpperCase().replace(/[^A-Z0-9]/g, '');
    }

    async setStatus(event) {
        const { id, status } = event.params;
        const labels = { en_cours: 'En cours', a_valider: 'À valider', valide: 'Validé', annule: 'Annulé' };
        const label = labels[status] || status;
        // Confirmation avant tout changement de statut. Les transitions « vers l'avant »
        // (À valider / Validé) sont irréversibles pour tout le monde sauf l'administrateur :
        // on l'indique explicitement pour éviter une soumission prématurée.
        let message;
        if (status === 'a_valider') {
            message = 'Soumettre cet inventaire à la validation ?\n\n⚠️ Action irréversible : une fois soumis, vous ne pourrez plus le modifier ni revenir en arrière. Seul un administrateur pourra le rouvrir.';
        } else if (status === 'valide') {
            message = 'Valider cet inventaire ?\n\n⚠️ Action irréversible : seul un administrateur pourra le rouvrir ensuite.';
        } else {
            message = `Changer le statut de cet inventaire vers « ${label} » ?`;
        }
        if (!window.confirm(message)) {
            return;
        }
        const res = await fetch(`/api/history/${encodeURIComponent(id)}/status`, {
            method: 'PATCH',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ status }),
        });
        if (!res.ok) {
            const data = await res.json().catch(() => ({}));
            window.alert(data.error || 'Échec du changement de statut.');
            return;
        }
        // Recharge pour recalculer les actions disponibles et badges.
        window.location.reload();
    }

    // Enregistre les concessions cochées dans le picker (modifiables tant que le scan n'est pas validé).
    async saveConcessions(event) {
        const { id } = event.params;
        const pickerEl = this.hasConcessionPickerTarget
            ? this.concessionPickerTarget.querySelector('[data-controller~="concession-picker-inline"]')
            : null;
        const picker = pickerEl
            ? this.application.getControllerForElementAndIdentifier(pickerEl, 'concession-picker-inline')
            : null;
        if (!picker) {
            window.alert('Sélecteur de concessions indisponible. Rechargez la page.');
            return;
        }
        const concessions = picker.selected();
        if (concessions.length === 0) {
            window.alert('Sélectionnez au moins une concession.');
            return;
        }
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = 'Enregistrement…';
        try {
            const res = await fetch(`/api/history/${encodeURIComponent(id)}/concessions`, {
                method: 'PATCH',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ concessions }),
            });
            const data = await res.json().catch(() => ({}));
            if (!res.ok) {
                window.alert(data.error || 'Échec de la modification des concessions.');
                btn.disabled = false;
                btn.textContent = previous;
                return;
            }
            window.location.reload();
        } catch (e) {
            window.alert('Erreur réseau lors de l’enregistrement.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    // Renomme l'inventaire (libellé) depuis le popover du titre sur la page détail.
    async renameInventory(event) {
        const { id } = event.params;
        const box = event.currentTarget.closest('details') || event.currentTarget.parentElement;
        const input = box ? box.querySelector('input[type="text"]') : null;
        if (!input) return;
        const label = input.value.trim();
        if (!label) {
            window.alert('Le nom ne peut pas être vide.');
            return;
        }
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = 'Enregistrement…';
        try {
            const res = await fetch(`/api/history/${encodeURIComponent(id)}/label`, {
                method: 'PATCH',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ label }),
            });
            const data = await res.json().catch(() => ({}));
            if (!res.ok) {
                window.alert(data.error || 'Échec du renommage.');
                btn.disabled = false;
                btn.textContent = previous;
                return;
            }
            window.location.reload();
        } catch (e) {
            window.alert('Erreur réseau lors du renommage.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    // Modifie le lieu de l'inventaire (obligatoire, non vide) tant qu'il n'est pas validé.
    async saveLocation(event) {
        const { id } = event.params;
        const box = event.currentTarget.closest('[data-location-edit]');
        const input = box ? box.querySelector('input[type="text"]') : null;
        if (!input) return;
        const locationNote = input.value.trim();
        if (!locationNote) {
            window.alert('Le lieu est obligatoire.');
            input.focus();
            return;
        }
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = 'Enregistrement…';
        try {
            const res = await fetch(`/api/history/${encodeURIComponent(id)}/location`, {
                method: 'PATCH',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ locationNote }),
            });
            const data = await res.json().catch(() => ({}));
            if (!res.ok) {
                window.alert(data.error || 'Échec de l’enregistrement du lieu.');
                btn.disabled = false;
                btn.textContent = previous;
                return;
            }
            window.location.reload();
        } catch (e) {
            window.alert('Erreur réseau lors de l’enregistrement du lieu.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    // Change le type de scan (VN/VO) tant que l'inventaire n'est pas validé.
    async saveScanType(event) {
        const { id, type } = event.params;
        const res = await fetch(`/api/history/${encodeURIComponent(id)}/type`, {
            method: 'PATCH',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ scanType: type }),
        });
        const data = await res.json().catch(() => ({}));
        if (!res.ok) {
            window.alert(data.error || 'Échec du changement de type.');
            return;
        }
        window.location.reload();
    }

    async archive(event) {
        const { id } = event.params;
        const res = await fetch(`/api/history/${encodeURIComponent(id)}/archive`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
        });
        if (!res.ok) {
            window.alert("Échec de l'archivage.");
            return;
        }
        window.location.reload();
    }

    async remove(event) {
        const { id } = event.params;
        if (!window.confirm('Supprimer définitivement cet inventaire ? Cette action est irréversible.')) {
            return;
        }
        const res = await fetch(`/api/history?id=${encodeURIComponent(id)}`, { method: 'DELETE' });
        if (!res.ok) {
            window.alert('Échec de la suppression.');
            return;
        }
        window.location.href = '/inventaires';
    }

    async export(event) {
        await this.download(event, '/api/export/xlsx', 'scan-vehicules.xlsx');
    }

    async exportPdfPhotos(event) {
        await this.download(event, '/api/export/pdf-photos', 'rapport-photos.pdf');
    }

    // Inventaire non validé : l'export « avec images » est bloqué (cf. ExportController::photosWeb).
    reportPhotosBlocked() {
        window.alert("L'export avec images n'est disponible que lorsque l'inventaire est validé.");
    }

    // ─── Sélection multiple → fusion en un nouvel inventaire ───

    toggleSelect(event) {
        const { id } = event.params;
        if (!this.selectedIds) this.selectedIds = new Set();
        if (event.currentTarget.checked) {
            this.selectedIds.add(id);
        } else {
            this.selectedIds.delete(id);
        }
        this.refreshMergeBar();
    }

    clearSelection() {
        this.selectedIds = new Set();
        this.element.querySelectorAll('input[type="checkbox"][data-action*="inventaires#toggleSelect"]')
            .forEach((cb) => { cb.checked = false; });
        this.refreshMergeBar();
    }

    refreshMergeBar() {
        const n = this.selectedIds ? this.selectedIds.size : 0;
        if (this.hasMergeCountTarget) this.mergeCountTarget.textContent = String(n);
        if (this.hasMergeBarTarget) {
            this.mergeBarTarget.classList.toggle('hidden', n === 0);
            this.mergeBarTarget.classList.toggle('flex', n > 0);
        }
    }

    async merge(event) {
        const ids = this.selectedIds ? Array.from(this.selectedIds) : [];
        if (ids.length < 2) {
            window.alert('Sélectionnez au moins deux inventaires à fusionner.');
            return;
        }
        // Propose un nom pour le nouvel inventaire (modifiable). Annuler = abandon de la fusion.
        const proposed = window.prompt(
            `Nom du nouvel inventaire (fusion de ${ids.length} inventaires « En cours », les originaux sont conservés) :`,
            `Fusion de ${ids.length} inventaires`,
        );
        if (proposed === null) {
            return;
        }
        const label = proposed.trim();
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = 'Fusion…';
        try {
            const res = await fetch('/api/history/merge', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ ids, label }),
            });
            const data = await res.json().catch(() => ({}));
            if (!res.ok || !data.id) {
                window.alert(data.error || 'Échec de la fusion.');
                btn.disabled = false;
                btn.textContent = previous;
                return;
            }
            window.location.href = `/inventaires/${data.id}`;
        } catch (e) {
            window.alert('Erreur réseau lors de la fusion.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    async download(event, endpoint, filename) {
        const { id } = event.params;
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = '…';
        try {
            const res = await fetch(endpoint, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ sessionId: id }),
            });
            if (!res.ok) {
                window.alert('Échec de la génération du fichier.');
                return;
            }
            const blob = await res.blob();
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            setTimeout(() => URL.revokeObjectURL(url), 1000);
        } catch (e) {
            window.alert('Erreur réseau lors de la génération du fichier.');
        } finally {
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    // ─── Édition des paires plaque/VIN (envoyé en fetch, comme les boutons de statut) ───

    async uploadPhoto(event) {
        const { id, index, slot } = event.params;
        // Le champ fichier est dans le même <details> que le bouton.
        const box = event.currentTarget.closest('details') || event.currentTarget.parentElement;
        const input = box ? box.querySelector('input[type="file"]') : null;
        if (!input || !input.files || input.files.length === 0) {
            window.alert('Veuillez d’abord choisir une photo.');
            return;
        }
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = 'Envoi…';
        try {
            if (this.s3Value) {
                await this.uploadPhotoS3(id, index, slot, input.files[0]);
            } else {
                const fd = new FormData();
                fd.append('photo', input.files[0]);
                const res = await fetch(`/inventaires/${encodeURIComponent(id)}/paires/${index}/photo/${slot}`, {
                    method: 'POST',
                    body: fd,
                });
                const data = await res.json().catch(() => ({}));
                if (!res.ok) {
                    window.alert(data.error || 'Échec de l’envoi de la photo.');
                    btn.disabled = false;
                    btn.textContent = previous;
                    return;
                }
            }
            window.location.reload();
        } catch (e) {
            window.alert((e && e.message) ? `Échec de l’envoi : ${e.message}` : 'Erreur réseau lors de l’envoi.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    // Remplacement de photo en mode S3 : compression → upload navigateur→S3 → re-OCR serveur.
    async uploadPhotoS3(id, index, slot, file) {
        const base64 = await compressToJpegBase64(file);
        const imageId = crypto.randomUUID();
        const { url, fields } = await s3Sign({ sessionId: id, imageId });
        const blobFile = new File([base64ToBlob(base64, 'image/jpeg')], `${imageId}.jpg`, { type: 'image/jpeg' });
        await s3FormUpload({ url, fields, file: blobFile });
        const res = await fetch(`/inventaires/${encodeURIComponent(id)}/paires/${index}/photo/${slot}/s3`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ imageId, image: base64, filename: file.name }),
        });
        const data = await res.json().catch(() => ({}));
        if (!res.ok) throw new Error(data.error || 'mise à jour refusée');
    }

    async deletePhoto(event) {
        const { id, index, slot } = event.params;
        if (!window.confirm('Supprimer cette photo ?')) {
            return;
        }
        const res = await fetch(`/inventaires/${encodeURIComponent(id)}/paires/${index}/photo/${slot}/supprimer`, { method: 'POST' });
        if (!res.ok) {
            window.alert('Échec de la suppression de la photo.');
            return;
        }
        window.location.reload();
    }

    async saveModel(event) {
        const { id, index } = event.params;
        // Les 2 champs (marque, modèle) sont dans le même <details> que le bouton.
        const box = event.currentTarget.closest('details') || event.currentTarget.parentElement;
        const makeInput = box ? box.querySelector('input[data-model-make]') : null;
        const modelInput = box ? box.querySelector('input[data-model-model]') : null;
        const make = makeInput ? makeInput.value.trim() : '';
        const model = modelInput ? modelInput.value.trim() : '';
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = 'Enregistrement…';
        try {
            const res = await fetch(`/inventaires/${encodeURIComponent(id)}/paires/${index}/marque-modele`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ make, model }),
            });
            const data = await res.json().catch(() => ({}));
            if (!res.ok) {
                window.alert(data.error || 'Échec de l’enregistrement.');
                btn.disabled = false;
                btn.textContent = previous;
                return;
            }
            window.location.reload();
        } catch (e) {
            window.alert('Erreur réseau lors de l’enregistrement.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    async editValue(event) {
        const { id, index, slot } = event.params;
        // Le champ texte est dans le même <details> que le bouton.
        const box = event.currentTarget.closest('details') || event.currentTarget.parentElement;
        const input = box ? box.querySelector('input[type="text"]') : null;
        if (!input) {
            return;
        }
        const value = input.value.trim();
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = 'Enregistrement…';
        try {
            const res = await fetch(`/inventaires/${encodeURIComponent(id)}/paires/${index}/valeur/${slot}`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ value }),
            });
            const data = await res.json().catch(() => ({}));
            if (!res.ok) {
                window.alert(data.error || 'Échec de l’enregistrement.');
                btn.disabled = false;
                btn.textContent = previous;
                return;
            }
            window.location.reload();
        } catch (e) {
            window.alert('Erreur réseau lors de l’enregistrement.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    // Supprime les véhicules en double (garde la 1ère occurrence de chaque plaque/VIN).
    async removeDuplicates(event) {
        const { id } = event.params;
        if (!window.confirm('Supprimer les véhicules en double ? La première occurrence de chaque véhicule est conservée ; les suivantes et leurs photos sont supprimées.')) {
            return;
        }
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = 'Suppression…';
        try {
            const res = await fetch(`/inventaires/${encodeURIComponent(id)}/paires/dedupe`, { method: 'POST' });
            const data = await res.json().catch(() => ({}));
            if (!res.ok) {
                window.alert(data.error || 'Échec de la suppression des doublons.');
                btn.disabled = false;
                btn.textContent = previous;
                return;
            }
            window.location.reload();
        } catch (e) {
            window.alert('Erreur réseau lors de la suppression des doublons.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    // Enregistre le commentaire d'un véhicule scanné/ajouté.
    async saveVehicleComment(event) {
        const { id, index } = event.params;
        const box = event.currentTarget.closest('[data-veh-comment]');
        const ta = box ? box.querySelector('textarea') : null;
        if (!ta) return;
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = 'Enregistrement…';
        try {
            const res = await fetch(`/inventaires/${encodeURIComponent(id)}/paires/${index}/commentaire`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ comment: ta.value }),
            });
            const data = await res.json().catch(() => ({}));
            if (!res.ok) {
                window.alert(data.error || 'Échec de l’enregistrement du commentaire.');
                btn.disabled = false;
                btn.textContent = previous;
                return;
            }
            btn.textContent = 'Enregistré ✓';
            setTimeout(() => { btn.disabled = false; btn.textContent = previous; }, 1500);
        } catch (e) {
            window.alert('Erreur réseau lors de l’enregistrement.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    async addPair(event) {
        const { id } = event.params;
        const res = await fetch(`/inventaires/${encodeURIComponent(id)}/paires/ajouter`, { method: 'POST' });
        if (!res.ok) {
            window.alert('Échec de l’ajout du véhicule.');
            return;
        }
        window.location.reload();
    }

    async deletePair(event) {
        const { id, index } = event.params;
        if (!window.confirm('Supprimer ce véhicule et ses photos ? Cette action est irréversible.')) {
            return;
        }
        const res = await fetch(`/inventaires/${encodeURIComponent(id)}/paires/${index}/supprimer`, { method: 'POST' });
        if (!res.ok) {
            window.alert('Échec de la suppression du véhicule.');
            return;
        }
        window.location.reload();
    }

    // ─── Déplacement d'une photo vers un autre véhicule (drag & drop, repli « Déplacer… ») ───

    dragStart(event) {
        const { index, slot } = event.params;
        event.dataTransfer.setData('application/x-scan-photo', JSON.stringify({ index, slot }));
        event.dataTransfer.effectAllowed = 'move';
    }

    dragOver(event) {
        // dataTransfer.getData est illisible pendant le survol : on teste le type uniquement.
        if (Array.from(event.dataTransfer.types).includes('application/x-scan-photo')) {
            event.preventDefault();
            event.dataTransfer.dropEffect = 'move';
            event.currentTarget.classList.add('ring-2', 'ring-blue-400');
        }
    }

    dragLeave(event) {
        event.currentTarget.classList.remove('ring-2', 'ring-blue-400');
    }

    async drop(event) {
        event.preventDefault();
        event.currentTarget.classList.remove('ring-2', 'ring-blue-400');
        const raw = event.dataTransfer.getData('application/x-scan-photo');
        if (!raw) return;
        const { index: from, slot } = JSON.parse(raw);
        const { id, index: to } = event.params;
        if (from === to) return;
        await this.doMovePhoto(id, from, slot, to);
    }

    // Repli sans drag & drop (mobile) : demande le numéro du véhicule cible.
    async movePrompt(event) {
        const { id, index, slot, count } = event.params;
        const answer = window.prompt(`Déplacer la photo ${slot} vers quel véhicule ? (1 à ${count})`);
        if (answer === null) return;
        const to = parseInt(answer, 10) - 1;
        if (Number.isNaN(to) || to < 0 || to >= count) {
            window.alert('Numéro de véhicule invalide.');
            return;
        }
        await this.doMovePhoto(id, index, slot, to);
    }

    async doMovePhoto(id, from, slot, to) {
        const res = await fetch(`/inventaires/${encodeURIComponent(id)}/paires/${from}/photo/${slot}/deplacer/${to}`, { method: 'POST' });
        const data = await res.json().catch(() => ({}));
        if (!res.ok) {
            window.alert(data.error || 'Échec du déplacement de la photo.');
            return;
        }
        // Mémorise le dernier déplacement pour proposer « Annuler » après rechargement.
        try {
            sessionStorage.setItem('scanPhotoUndo', JSON.stringify({
                sessionId: id,
                slot,
                from,
                targetIndex: data.targetIndex ?? to,
                sourceRemoved: !!data.sourceRemoved,
                message: data.message || 'Photo déplacée.',
                ts: Date.now(),
            }));
        } catch (e) { /* stockage indisponible : pas d'annulation proposée */ }
        window.location.reload();
    }

    // ─── Annulation du dernier déplacement (bannière affichée après rechargement) ───

    connect() {
        this.selectedIds = new Set();
        this.maybeShowUndoBanner();
    }

    maybeShowUndoBanner() {
        let info = null;
        try {
            info = JSON.parse(sessionStorage.getItem('scanPhotoUndo') || 'null');
        } catch (e) { /* JSON corrompu : on ignore */ }
        if (!info) return;
        if (Date.now() - info.ts > 10 * 60 * 1000) {
            sessionStorage.removeItem('scanPhotoUndo');
            return;
        }
        // Uniquement sur la page de détail de l'inventaire concerné.
        if (window.location.pathname !== `/inventaires/${info.sessionId}`) return;

        const banner = document.createElement('div');
        banner.className = 'flex flex-wrap items-center justify-between gap-3 bg-blue-50 border border-blue-200 text-blue-900 rounded-2xl px-4 py-3 text-sm';
        const text = document.createElement('span');
        text.textContent = info.message;
        const actions = document.createElement('span');
        actions.className = 'flex items-center gap-2 shrink-0';
        const undoBtn = document.createElement('button');
        undoBtn.type = 'button';
        undoBtn.textContent = 'Annuler le déplacement';
        undoBtn.className = 'px-3 py-1.5 text-xs font-medium bg-white text-blue-700 border border-blue-300 rounded-lg hover:bg-blue-100 transition-colors';
        undoBtn.addEventListener('click', () => this.undoMove(info, undoBtn));
        const closeBtn = document.createElement('button');
        closeBtn.type = 'button';
        closeBtn.textContent = '✕';
        closeBtn.title = 'Ignorer';
        closeBtn.className = 'p-1 text-blue-400 hover:text-blue-700 transition-colors';
        closeBtn.addEventListener('click', () => {
            sessionStorage.removeItem('scanPhotoUndo');
            banner.remove();
        });
        actions.append(undoBtn, closeBtn);
        banner.append(text, actions);
        this.element.prepend(banner);
    }

    async undoMove(info, btn) {
        btn.disabled = true;
        btn.textContent = 'Annulation…';
        try {
            let dest = info.from;
            if (info.sourceRemoved) {
                // Le véhicule source a été supprimé lors de la fusion : on recrée d'abord
                // un véhicule vide (en fin de liste) pour y remettre la photo.
                const count = document.querySelectorAll('[data-action*="inventaires#drop"]').length;
                const resAdd = await fetch(`/inventaires/${encodeURIComponent(info.sessionId)}/paires/ajouter`, { method: 'POST' });
                if (!resAdd.ok) throw new Error("Impossible de recréer le véhicule d'origine.");
                dest = count; // index du véhicule fraîchement ajouté (en fin de liste)
            }
            const res = await fetch(`/inventaires/${encodeURIComponent(info.sessionId)}/paires/${info.targetIndex}/photo/${info.slot}/deplacer/${dest}`, { method: 'POST' });
            const data = await res.json().catch(() => ({}));
            if (!res.ok) throw new Error(data.error || '');
            sessionStorage.removeItem('scanPhotoUndo');
            window.location.reload();
        } catch (e) {
            window.alert(e.message || 'Échec de l\'annulation du déplacement.');
            btn.disabled = false;
            btn.textContent = 'Annuler le déplacement';
        }
    }

    // ─── Autres documents (pièces jointes) — fetch, comme les boutons de statut ───

    async uploadDocuments(event) {
        const { id } = event.params;
        const box = event.currentTarget.closest('[data-doc-upload]');
        const fileInput = box ? box.querySelector('input[type="file"]') : null;
        const commentInput = box ? box.querySelector('textarea') : null;
        if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
            window.alert('Veuillez sélectionner au moins un fichier.');
            return;
        }
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = 'Envoi…';
        try {
            const fd = new FormData();
            for (const f of fileInput.files) {
                fd.append('files[]', f);
            }
            if (commentInput && commentInput.value) {
                fd.append('comment', commentInput.value);
            }
            const res = await fetch(`/inventaires/${encodeURIComponent(id)}/documents`, { method: 'POST', body: fd });
            const data = await res.json().catch(() => ({}));
            if (!res.ok) {
                window.alert(data.error || 'Échec de l’envoi.');
                btn.disabled = false;
                btn.textContent = previous;
                return;
            }
            window.location.reload();
        } catch (e) {
            window.alert('Erreur réseau lors de l’envoi.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }

    async deleteDocument(event) {
        const { id, att } = event.params;
        if (!window.confirm('Supprimer définitivement ce document ?')) {
            return;
        }
        const res = await fetch(`/inventaires/${encodeURIComponent(id)}/documents/${att}/supprimer`, { method: 'POST' });
        if (!res.ok) {
            window.alert('Échec de la suppression.');
            return;
        }
        window.location.reload();
    }

    async editComment(event) {
        const { id, att } = event.params;
        const box = event.currentTarget.closest('details') || event.currentTarget.parentElement;
        const ta = box ? box.querySelector('textarea') : null;
        const btn = event.currentTarget;
        const previous = btn.textContent;
        btn.disabled = true;
        btn.textContent = '…';
        try {
            const fd = new FormData();
            fd.append('comment', ta ? ta.value : '');
            const res = await fetch(`/inventaires/${encodeURIComponent(id)}/documents/${att}/commentaire`, { method: 'POST', body: fd });
            if (!res.ok) {
                window.alert('Échec de l’enregistrement du commentaire.');
                btn.disabled = false;
                btn.textContent = previous;
                return;
            }
            window.location.reload();
        } catch (e) {
            window.alert('Erreur réseau.');
            btn.disabled = false;
            btn.textContent = previous;
        }
    }
}
