/**
 * Fichier  : assets/js/pages/settings.js
 * Auteur   : KREMER Régis
 * Version  : 2.6.102
 * Date     : 2026-07-21
 * Description : JS — Paramètres : config, backup, push, archivage annuel, danger
 *
 * Changelog :
 *   v2.2.1 — Fix IDs, handlers backup/restore
 *   v2.5.0 — Module archivage, reminder annuel, push device info, layout settings
 *   v2.6.8 — Messages push Android/iOS/PWA, statut appareil plus clair
 *   v2.6.14 — Logo entreprise : aperçu, upload, remplacement et suppression
 *   v2.6.17 — Preview active claire et synchronisation du logo shell après upload/suppression
 *   v2.6.18 — Preview existante persistante, logo shell via proxy image et textes paramètres simplifiés
 *   v2.6.24 — Cohérence finale : synchronisation sidebar + menu mobile du logo entreprise
 *   v2.6.70 — I18N CORE LOCALE CURRENCY1 : pays, locale, devise et aperçu Intl sans conversion.
 *   v2.6.84 — ADMIN COMPLEX FORMS8 : repli compatible avec les confirmations serveur renforcées.
 *   v2.6.102 — Initialisation du module LDAP/Active Directory sécurisé.
 */

// ================================================================
// settings.js — Paramètres
// ================================================================
const SetPage = {

    async init() {
        const root = document.getElementById('pgSettings');
        if (!root) return;

        this.initLangGrid();

        const $ = (id) => document.getElementById(id);

        const inpCompany = $('settCompanyName');
        const inpSku     = $('settSkuPrefix');
        const inpCountry = $('settCountry');
        const inpLocale  = $('settLocale');
        const inpCurrency= $('settCurrency');
        const btnSave    = $('btnSaveSettings');
        const logoInput  = $('companyLogoInput');
        const logoChoose = $('btnChooseCompanyLogo');
        const logoUpload = $('btnUploadCompanyLogo');
        const logoDelete = $('btnDeleteCompanyLogo');
        const btnBackup  = $('btnBackup');
        const btnRestore = $('btnRestore');
        const fileInput  = $('restoreFileInput');
        const btnDelProd = $('btnDeleteProducts');
        const btnDelMov  = $('btnDeleteMovements');
        const btnDelAll  = $('btnDeleteAll');

        // Charger settings
        try {
            const s = await Api.settings();
            if (inpCompany) inpCompany.value = s.companyName || '';
            if (inpSku)     inpSku.value     = s.skuPrefix   || 'PRD-';
            this.renderLocaleCurrencySettings(s, inpCountry, inpLocale, inpCurrency);
            this.renderCompanyLogo(s);
        } catch (e) {
            toast(e.message || 'Impossible de charger les paramètres', 'error');
        }

        // Save
        if (btnSave) btnSave.onclick = () => this.saveSettings(inpCompany, inpSku, inpCountry, inpLocale, inpCurrency);
        if (inpCountry) inpCountry.addEventListener('change', () => {
            const recommended = this._countryCurrencyMap?.[inpCountry.value];
            if (recommended && inpCurrency) inpCurrency.value = recommended;
            this.updateLocaleCurrencyPreview(inpLocale, inpCurrency);
        });
        [inpLocale, inpCurrency].filter(Boolean).forEach(field => {
            field.addEventListener('change', () => this.updateLocaleCurrencyPreview(inpLocale, inpCurrency));
        });

        // Logo entreprise
        if (logoChoose && logoInput) logoChoose.onclick = () => logoInput.click();
        if (logoInput && logoUpload) {
            logoInput.onchange = () => {
                const file = logoInput.files && logoInput.files[0];
                logoUpload.disabled = !file;
                if (file) this.previewSelectedCompanyLogo(file);
            };
            logoUpload.onclick = () => this.uploadCompanyLogo(logoInput, logoUpload);
        }
        if (logoDelete) logoDelete.onclick = () => this.deleteCompanyLogo();

        // Backup export
        if (btnBackup) {
            btnBackup.onclick = () => {
                try { Api.backupExport(); }
                catch (e) { toast(e.message || 'Export impossible', 'error'); }
            };
        }

        // Backup import
        if (btnRestore && fileInput) {
            btnRestore.onclick = () => fileInput.click();
            fileInput.onchange = async () => {
                const f = fileInput.files && fileInput.files[0];
                if (!f) return;
                if (!confirm("Importer cette sauvegarde ?\n\nCette action remplace vos données actuelles.\nAssurez-vous d'avoir exporté avant.")) {
                    fileInput.value = '';
                    return;
                }
                try {
                    const json = JSON.parse(await f.text());
                    await Api.backupImport(json, 'RESTAURER');
                    toast('Sauvegarde importée', 'success');
                    setTimeout(() => location.reload(), 800);
                } catch (e) {
                    toast(e.message || 'Import impossible (JSON invalide ?)', 'error');
                } finally {
                    fileInput.value = '';
                }
            };
        }

        // Danger zone
        if (btnDelProd) btnDelProd.onclick = () => this.clearEntity('products', 'tous les produits et leur stock');
        if (btnDelMov)  btnDelMov.onclick  = () => this.clearEntity('movements', 'tous les mouvements');
        if (btnDelAll)  btnDelAll.onclick  = () => this.clearAll();

        // Push — initialiser l'UI
        this.initPushUI();

        // Archivage
        await this.loadArchive();

        // LDAP / Active Directory
        if (typeof LdapSettingsPage !== 'undefined') await LdapSettingsPage.init();
    },

    // ══════════════════════════════════════════════════════════════
    // SETTINGS SAVE
    // ══════════════════════════════════════════════════════════════
    async saveSettings(inpCompany, inpSku, inpCountry, inpLocale, inpCurrency) {
        try {
            const companyName = (inpCompany ? inpCompany.value : '').trim();
            const skuPrefix   = (inpSku ? inpSku.value : '').trim() || 'PRD-';
            const country     = (inpCountry ? inpCountry.value : 'FR').trim().toUpperCase();
            const locale      = (inpLocale ? inpLocale.value : 'auto').trim();
            const currency    = (inpCurrency ? inpCurrency.value : 'EUR').trim().toUpperCase();
            await Api.settingsSave({ companyName, skuPrefix, country, locale, currency });
            toast('Paramètres sauvegardés', 'success');
            location.reload();
        } catch (e) {
            toast(e.message || 'Erreur sauvegarde paramètres', 'error');
        }
    },


    // ══════════════════════════════════════════════════════════════
    // LOCALE / PAYS / DEVISE
    // ══════════════════════════════════════════════════════════════
    renderLocaleCurrencySettings(settings, countrySelect, localeSelect, currencySelect) {
        const localeOptions = Array.isArray(settings?.localeOptions) ? settings.localeOptions : [];
        const countryOptions = Array.isArray(settings?.countryOptions) ? settings.countryOptions : [];
        const currencyOptions = Array.isArray(settings?.currencyOptions) ? settings.currencyOptions : [];
        this._countryCurrencyMap = Object.fromEntries(countryOptions.map(option => [String(option.code || ''), String(option.defaultCurrency || '')]));

        const fill = (select, options, selected, labelBuilder) => {
            if (!select) return;
            select.innerHTML = options.map(option => {
                const code = String(option.code || '');
                const label = labelBuilder(option);
                return `<option value="${this._esc(code)}" ${code === selected ? 'selected' : ''}>${this._esc(label)}</option>`;
            }).join('');
        };

        fill(countrySelect, countryOptions, String(settings?.country || 'FR'), option => `${Locale.displayRegion(option.code, option.label)} (${option.code})`);
        fill(localeSelect, localeOptions, String(settings?.locale || 'auto'), option => option.code === 'auto'
            ? window.t('settings.locale.auto', 'Automatique selon la langue')
            : `${Locale.displayLocale(option.code, option.label)} — ${option.code}`);
        fill(currencySelect, currencyOptions, String(settings?.currency || 'EUR'), option => `${option.code} — ${Locale.displayCurrency(option.code, option.label)}`);
        this.updateLocaleCurrencyPreview(localeSelect, currencySelect);
    },

    updateLocaleCurrencyPreview(localeSelect, currencySelect) {
        const amount = document.getElementById('settingsLocalePreviewAmount');
        if (!amount) return;
        const configuredLocale = localeSelect?.value || 'auto';
        const locale = configuredLocale === 'auto'
            ? (window.I18N?.LANG_LOCALES?.[window.SM_LANG] || window.Locale?.locale || 'fr-FR')
            : configuredLocale;
        const currency = currencySelect?.value || window.Locale?.currency || 'EUR';
        try {
            amount.textContent = new Intl.NumberFormat(locale, { style:'currency', currency }).format(1234.56);
        } catch (_error) {
            amount.textContent = `1 234,56 ${currency}`;
        }
    },


    // ══════════════════════════════════════════════════════════════
    // LOGO ENTREPRISE
    // ══════════════════════════════════════════════════════════════
    renderCompanyLogo(settings) {
        const img = document.getElementById('companyLogoImg');
        const fallback = document.getElementById('companyLogoFallback');
        const status = document.getElementById('companyLogoStatus');
        const del = document.getElementById('btnDeleteCompanyLogo');
        const upload = document.getElementById('btnUploadCompanyLogo');
        const input = document.getElementById('companyLogoInput');
        const hint = document.getElementById('companyLogoActiveHint');
        const path = document.getElementById('companyLogoPath');
        const panel = document.getElementById('companyLogoPanel');

        const savedPath = settings && settings.logoUrl ? String(settings.logoUrl).trim() : '';
        const available = !!(settings && settings.logoAvailable && (settings.logoPublicUrl || savedPath));
        const url = available
            ? (settings.logoPublicUrl || ((typeof Api !== 'undefined' && typeof Api.imageUrl === 'function') ? Api.imageUrl(savedPath) : savedPath))
            : '';
        const displayUrl = url ? url + (url.includes('?') ? '&' : '?') + 'v=' + Date.now() : '';

        if (img) {
            if (available) {
                img.src = displayUrl;
                img.alt = 'Logo entreprise actuellement utilisé';
                img.hidden = false;
            } else {
                img.removeAttribute('src');
                img.alt = '';
                img.hidden = true;
            }
        }

        if (fallback) fallback.hidden = available;
        if (panel) {
            panel.classList.toggle('is-active', available);
            panel.classList.toggle('is-missing', !!savedPath && !available);
        }

        if (status) {
            if (available) status.textContent = 'Logo actif';
            else if (savedPath) status.textContent = 'Logo introuvable';
            else status.textContent = 'Aucun logo';
            status.classList.toggle('is-ok', available);
            status.classList.toggle('is-warning', !!savedPath && !available);
            status.classList.remove('is-pending');
        }

        if (hint) {
            if (available) hint.textContent = 'Ce logo est actif : il remplace le texte de l’entreprise dans le menu et il est utilisé dans les impressions compatibles.';
            else if (savedPath) hint.textContent = 'Un chemin de logo est enregistré, mais le fichier n’est pas trouvé sur le serveur. Envoyez à nouveau le logo ou supprimez l’ancien chemin.';
            else if (settings && settings.logoStorageReady === false) hint.textContent = 'Le dossier uploads/company/ n’est pas accessible en écriture : corrigez les droits serveur avant d’envoyer un logo.';
            else hint.textContent = 'Ajoutez un logo pour remplacer le texte de l’entreprise dans le menu et personnaliser les impressions.';
            hint.classList.toggle('is-ok', available);
        }

        if (path) {
            if (savedPath) {
                path.hidden = false;
                path.textContent = 'Chemin enregistré : ' + savedPath + (settings && settings.logoAvailable === false ? ' · fichier non trouvé' : '');
            } else {
                path.hidden = true;
                path.textContent = '';
            }
        }

        if (del) del.hidden = !savedPath;
        if (upload) upload.disabled = true;
        if (input) input.value = '';
        this.syncCompanyLogoShell(available ? displayUrl : '', settings);
    },
    previewSelectedCompanyLogo(file) {
        const img = document.getElementById('companyLogoImg');
        const fallback = document.getElementById('companyLogoFallback');
        const status = document.getElementById('companyLogoStatus');
        if (!file) return;
        if (file.size > 2 * 1024 * 1024) {
            toast('Logo trop lourd : 2 Mo maximum.', 'error');
            const input = document.getElementById('companyLogoInput');
            const upload = document.getElementById('btnUploadCompanyLogo');
            if (input) input.value = '';
            if (upload) upload.disabled = true;
            return;
        }
        const allowed = ['image/png','image/jpeg','image/webp','image/gif'];
        if (!allowed.includes(file.type)) {
            toast('Format logo non accepté. Utilisez PNG, JPG, WEBP ou GIF.', 'error');
            const input = document.getElementById('companyLogoInput');
            const upload = document.getElementById('btnUploadCompanyLogo');
            if (input) input.value = '';
            if (upload) upload.disabled = true;
            return;
        }
        if (img) {
            img.src = URL.createObjectURL(file);
            img.onload = () => URL.revokeObjectURL(img.src);
            img.hidden = false;
        }
        if (fallback) fallback.hidden = true;
        if (status) {
            status.textContent = 'Preview — à envoyer';
            status.classList.add('is-pending');
            status.classList.remove('is-ok');
        }
        const hint = document.getElementById('companyLogoActiveHint');
        if (hint) {
            hint.textContent = 'Aperçu local uniquement : cliquez sur “Envoyer le logo” pour l’utiliser réellement.';
            hint.classList.remove('is-ok');
        }
    },

    syncCompanyLogoShell(url, settings) {
        const rt = window.MageStockRuntime || {};
        const company = (settings && settings.companyName) || rt.companyName || 'MageStock';
        const appLogo = rt.appLogoUrl || (typeof Api !== 'undefined' ? Api.publicUrl('assets/img/sm.png') : 'assets/img/sm.png');
        if (settings && settings.logoPublicUrl !== undefined) rt.companyLogoUrl = url || '';

        const sidebarLogo = document.querySelector('.sidebar-logo');
        if (sidebarLogo) sidebarLogo.classList.toggle('sidebar-logo--with-company-logo', !!url);

        const icon = document.querySelector('.sidebar .logo-icon');
        if (icon) icon.classList.remove('company-logo-icon');

        const img = document.querySelector('.sidebar .logo-icon .logo-img');
        if (img) {
            img.src = appLogo;
            img.alt = 'MageStock';
        }

        if (sidebarLogo) {
            let text = sidebarLogo.querySelector('.logo-text');
            if (!text) {
                text = document.createElement('span');
                text.className = 'logo-text';
                sidebarLogo.appendChild(text);
            }
            if (url) {
                text.className = 'logo-text logo-text--company-logo';
                text.innerHTML = '';
                const logo = document.createElement('img');
                logo.src = url;
                logo.alt = company;
                logo.className = 'company-wordmark-img';
                text.appendChild(logo);
            } else {
                text.className = 'logo-text';
                text.textContent = company;
            }
        }

        const slideBrand = document.querySelector('.slide-menu-brand');
        if (slideBrand) {
            slideBrand.classList.toggle('slide-menu-brand--with-company-logo', !!url);
            let slideLogo = slideBrand.querySelector('.slide-menu-logo');
            if (slideLogo) {
                slideLogo.src = appLogo;
                slideLogo.alt = 'MageStock';
                slideLogo.classList.remove('company-logo-icon');
            }
            let slideTitle = slideBrand.querySelector('.slide-menu-title');
            if (!slideTitle) {
                slideTitle = document.createElement('span');
                slideTitle.className = 'slide-menu-title';
                slideBrand.appendChild(slideTitle);
            }
            if (url) {
                slideTitle.className = 'slide-menu-title slide-menu-title--company-logo';
                slideTitle.innerHTML = '';
                const logo = document.createElement('img');
                logo.src = url;
                logo.alt = company;
                logo.className = 'company-wordmark-img';
                slideTitle.appendChild(logo);
            } else {
                slideTitle.className = 'slide-menu-title';
                slideTitle.textContent = company;
            }
        }
    },

    async uploadCompanyLogo(input, button) {
        const file = input && input.files && input.files[0];
        if (!file) return;
        const oldText = button ? button.textContent : '';
        try {
            if (button) { button.disabled = true; button.textContent = 'Envoi…'; }
            const fd = new FormData();
            fd.append('logo', file);
            const settings = await Api.settingsLogoUpload(fd);
            this.renderCompanyLogo(settings);
            toast('Logo entreprise enregistré', 'success');
        } catch (e) {
            toast(e.message || 'Impossible d’envoyer le logo', 'error');
        } finally {
            if (button) { button.textContent = oldText || 'Envoyer le logo'; button.disabled = true; }
        }
    },

    async deleteCompanyLogo() {
        if (!confirm('Supprimer le logo entreprise ?\n\nLe logo MageStock sera utilisé en repli.')) return;
        try {
            const settings = await Api.settingsLogoDelete();
            this.renderCompanyLogo(settings);
            toast('Logo entreprise supprimé', 'success');
        } catch (e) {
            toast(e.message || 'Suppression du logo impossible', 'error');
        }
    },

    // ══════════════════════════════════════════════════════════════
    // PUSH NOTIFICATIONS — UI enrichie
    // ══════════════════════════════════════════════════════════════
    initPushUI() {
        const unsupEl = document.getElementById('pushUnsupported');
        const suppEl  = document.getElementById('pushSupported');

        const support = (window.SMPush && window.SMPush.getSupportInfo)
            ? window.SMPush.getSupportInfo()
            : { supported: ('serviceWorker' in navigator) && ('PushManager' in window) && ('Notification' in window), message: 'Navigateur non compatible.' };
        if (!support.supported) {
            if (unsupEl) {
                unsupEl.style.display = 'flex';
                unsupEl.innerHTML = '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg><span>'+this._esc(support.message)+'</span>';
            }
            if (suppEl)  suppEl.style.display  = 'none';
            return;
        }

        if (unsupEl) unsupEl.style.display = 'none';
        if (suppEl)  suppEl.style.display  = 'block';

        // Afficher info appareil si déjà abonné
        this._refreshPushDeviceInfo();
    },

    _refreshPushDeviceInfo() {
        const infoEl = document.getElementById('pushDeviceInfo');
        if (!infoEl) return;

        const support = (window.SMPush && window.SMPush.getSupportInfo) ? window.SMPush.getSupportInfo() : {supported:false,message:'Notifications non initialisées.'};
        const permission = (window.SMPush && window.SMPush.getPermissionState) ? window.SMPush.getPermissionState() : 'default';
        const isSubscribed = (window.SMPush && window.SMPush.isSubscribed);
        if (!support.supported) {
            infoEl.style.display = 'flex';
            infoEl.innerHTML = `<span>${this._esc(support.message)}</span>`;
            return;
        }
        if (!isSubscribed) {
            infoEl.style.display = 'flex';
            infoEl.innerHTML = `<span>Compatible sur cet appareil. Statut autorisation : <strong>${this._esc(permission)}</strong>. Cliquez sur “Activer sur cet appareil”.</span>`;
            return;
        }

        const ua   = navigator.userAgent;
        let browser = 'Navigateur inconnu';
        if (ua.includes('Edg/'))    browser = 'Microsoft Edge';
        else if (ua.includes('Chrome/'))  browser = 'Google Chrome';
        else if (ua.includes('Firefox/')) browser = 'Mozilla Firefox';
        else if (ua.includes('Safari/'))  browser = 'Safari';

        const os = ua.includes('Windows') ? 'Windows'
                 : ua.includes('Mac')     ? 'macOS'
                 : ua.includes('Linux')   ? 'Linux'
                 : ua.includes('Android') ? 'Android'
                 : ua.includes('iPhone') || ua.includes('iPad') ? 'iOS'
                 : 'OS inconnu';

        infoEl.style.display = 'flex';
        infoEl.innerHTML = `
            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink:0;margin-top:1px">
                <rect x="5" y="2" width="14" height="20" rx="2" ry="2"/>
                <line x1="12" y1="18" x2="12.01" y2="18"/>
            </svg>
            <span>Cet appareil est abonné — <strong>${browser}</strong> sur <strong>${os}</strong>. Autorisation : <strong>${this._esc(permission)}</strong></span>
        `;
    },

    // ══════════════════════════════════════════════════════════════
    // ARCHIVAGE
    // ══════════════════════════════════════════════════════════════
    async loadArchive() {
        try {
            // Statut (rappel annuel)
            const status = await Api.archiveStatus();

            if (status.needsReminder) {
                const reminder = document.getElementById('archiveReminder');
                if (reminder) reminder.style.display = 'flex';
            }

            const infoEl = document.getElementById('lastArchiveInfo');
            if (infoEl) {
                infoEl.textContent = status.lastArchiveAt
                    ? 'Dernier archivage : ' + this._fmtDate(status.lastArchiveAt)
                    : 'Aucun archivage effectué';
            }

            // Checkboxes entités avec comptages live
            await this._renderEntityChecks();

            // Liste des archives
            await this._renderArchiveList();

        } catch (e) {
            console.error('[Archive] Erreur chargement:', e);
        }
    },

    async _renderEntityChecks() {
        const container = document.getElementById('archiveEntityChecks');
        if (!container) return;

        const ENTITIES = [
            { key: 'products',         label: 'Produits',         icon: '📦' },
            { key: 'stock',            label: 'Stock',            icon: '🏪' },
            { key: 'movements',        label: 'Mouvements',       icon: '🔄' },
            { key: 'inventories',      label: 'Inventaires',      icon: '📋' },
            { key: 'orders',           label: 'Commandes',        icon: '🛒' },
            { key: 'alerts',           label: 'Alertes',          icon: '⚠️' },
            { key: 'product_versions', label: 'Versions produits', icon: '📝' },
        ];

        // Charger les comptages via backup (approximatif — on utilise les API existantes)
        const counts = {};
        try {
            const [prods, movs] = await Promise.all([Api.products(), Api.movements?.() || []]);
            counts.products  = prods.length;
            counts.movements = movs.length;
        } catch(e) {}

        container.innerHTML = ENTITIES.map(e => `
            <label class="archive-entity-check">
                <input type="checkbox" class="archive-entity-cb" value="${e.key}" checked>
                <span class="archive-entity-icon">${e.icon}</span>
                <span class="archive-entity-label">${e.label}</span>
                ${counts[e.key] !== undefined ? `<span class="archive-entity-count">${counts[e.key]}</span>` : ''}
            </label>
        `).join('');
    },

    async _renderArchiveList() {
        const container = document.getElementById('archiveList');
        if (!container) return;

        try {
            const archives = await Api.archiveList();

            if (!archives.length) {
                container.innerHTML = `<div class="archive-empty">
                    <svg viewBox="0 0 24 24" width="32" height="32" fill="none" stroke="currentColor" stroke-width="1.5">
                        <path d="M21 8v13H3V8"/><path d="M1 3h22v5H1z"/><line x1="10" y1="12" x2="14" y2="12"/>
                    </svg>
                    <p>Aucune archive — créez votre première archive ci-dessus.</p>
                </div>`;
                return;
            }

            container.innerHTML = `
                <div class="archive-table-wrap">
                    <table class="data-table">
                        <thead>
                            <tr>
                                <th>Libellé</th>
                                <th>Année</th>
                                <th>Date de création</th>
                                <th>Contenu</th>
                                <th class="cell-number">Taille</th>
                                <th class="cell-actions">Actions</th>
                            </tr>
                        </thead>
                        <tbody>
                            ${archives.map(a => `
                                <tr>
                                    <td><strong>${this._esc(a.label)}</strong></td>
                                    <td>${a.year || '—'}</td>
                                    <td>${this._fmtDate(a.createdAt)}</td>
                                    <td>
                                        <div class="archive-pills">
                                            ${(a.entities||[]).map(e => `
                                                <span class="archive-pill">${e}${a.counts?.[e] ? ' <em>('+a.counts[e]+')</em>' : ''}</span>
                                            `).join('')}
                                        </div>
                                    </td>
                                    <td class="cell-number">${a.sizeHuman}</td>
                                    <td style="display:flex;gap:4px">
                                        <button class="btn btn-sm btn-secondary" title="Lire l'archive" onclick="SetPage.readArchive('${this._esc(a.file)}')">
                                            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
                                        </button>
                                        <button class="btn btn-sm btn-warning" title="Restaurer" onclick="SetPage.restoreArchive('${this._esc(a.file)}', '${this._esc(a.label)}')">
                                            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 102.13-9.36L1 10"/></svg>
                                        </button>
                                        <button class="btn btn-sm btn-danger" title="Supprimer" onclick="SetPage.deleteArchive('${this._esc(a.file)}', '${this._esc(a.label)}')">
                                            ${Icons.trash}
                                        </button>
                                    </td>
                                </tr>
                            `).join('')}
                        </tbody>
                    </table>
                </div>`;
        } catch (e) {
            container.innerHTML = `<div style="color:var(--red);padding:12px">Erreur chargement des archives</div>`;
        }
    },

    async createArchive() {
        const label    = document.getElementById('archiveLabel')?.value?.trim() || '';
        const year     = document.getElementById('archiveYear')?.value || String(new Date().getFullYear() - 1);
        const checked  = [...document.querySelectorAll('.archive-entity-cb:checked')].map(cb => cb.value);

        if (!checked.length) { toast('Sélectionnez au moins une entité à archiver', 'warning'); return; }

        const fullLabel = label || `Archive ${year}`;

        if (!confirm(`Créer l'archive "${fullLabel}" ?\n\nEntités : ${checked.join(', ')}\n\nCette opération peut prendre quelques secondes.`)) return;

        const btn = document.getElementById('btnCreateArchive');
        if (btn) { btn.disabled = true; btn.textContent = 'Archivage…'; }

        try {
            const res = await Api.archiveCreate({ label: fullLabel, year, entities: checked });
            toast(`Archive créée — ${res.sizeHuman} (${Object.values(res.counts||{}).reduce((a,b)=>a+b,0)} enregistrements)`, 'success');
            document.getElementById('archiveLabel').value = '';
            await this._renderArchiveList();
            // Mettre à jour l'info dernier archivage
            const infoEl = document.getElementById('lastArchiveInfo');
            if (infoEl) infoEl.textContent = 'Dernier archivage : ' + this._fmtDate(new Date().toISOString());
            // Masquer le rappel
            const reminder = document.getElementById('archiveReminder');
            if (reminder) reminder.style.display = 'none';
        } catch (e) {
            toast(e.message || 'Erreur création archive', 'error');
        } finally {
            if (btn) { btn.disabled = false; btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 8v13H3V8"/><path d="M1 3h22v5H1z"/></svg> Créer l\'archive'; }
        }
    },

    async readArchive(file) {
        try {
            const archive = await Api.archiveRead(file);

            const entities = Object.keys(archive.data || {});
            let html = `
                <div style="margin-bottom:16px">
                    <strong>${this._esc(archive.label || file)}</strong>
                    <span class="text-muted" style="margin-left:8px;font-size:12px">
                        Créé le ${this._fmtDate(archive.createdAt)} par ${this._esc(archive.createdBy || '?')}
                    </span>
                </div>
                <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px">
                    ${entities.map(e => {
                        const items = archive.data[e] || [];
                        return `<div class="archive-read-card">
                            <div class="archive-read-entity">${this._esc(e)}</div>
                            <div class="archive-read-count">${items.length} enregistrements</div>
                        </div>`;
                    }).join('')}
                </div>`;

            Modal.show('Contenu de l\'archive', html, [
                { label: 'Fermer', cls: 'btn-secondary', onclick: () => Modal.close() },
                { label: 'Restaurer', cls: 'btn-warning', onclick: () => { Modal.close(); this.restoreArchive(file, archive.label); } },
            ], 'info');

        } catch (e) {
            toast(e.message || 'Erreur lecture archive', 'error');
        }
    },

    async restoreArchive(file, label) {
        if (!confirm(`Restaurer l'archive "${label}" ?\n\nATTENTION : Les données actuelles seront remplacées par celles de l'archive pour les entités archivées.\n\nCette action est irréversible.`)) return;
        try {
            const res = await Api.archiveRestore(file, 'RESTAURER');
            const total = Object.values(res.restored || {}).reduce((a,b) => a+b, 0);
            toast(`Archive restaurée — ${total} enregistrements remis en place`, 'success');
            setTimeout(() => location.reload(), 1200);
        } catch (e) {
            toast(e.message || 'Erreur restauration', 'error');
        }
    },

    async deleteArchive(file, label) {
        if (!confirm(`Supprimer définitivement l'archive "${label}" ?`)) return;
        try {
            await Api.archiveDelete(file, 'SUPPRIMER');
            toast('Archive supprimée', 'success');
            await this._renderArchiveList();
        } catch (e) {
            toast(e.message || 'Erreur suppression archive', 'error');
        }
    },

    scrollToArchive() {
        const el = document.getElementById('archiveSection');
        if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
    },

    // ══════════════════════════════════════════════════════════════
    // DANGER ZONE
    // ══════════════════════════════════════════════════════════════
    async clearEntity(entity, label) {
        if (!confirm('Supprimer ' + label + ' ? IRRÉVERSIBLE !')) return;
        try {
            if (entity === 'products') {
                const prods = await Api.products();
                for (const p of prods) await Api.prodDel(p.id);
            } else if (entity === 'movements') {
                await Api.mvClear();
            }
            toast(label.charAt(0).toUpperCase() + label.slice(1) + ' supprimé(s)', 'success');
            location.reload();
        } catch (e) {
            toast(e.message || 'Erreur suppression', 'error');
        }
    },

    async clearAll() {
        if (!confirm(
            "SUPPRIMER TOUTES LES DONNÉES ?\n\n" +
            "Produits, stock, mouvements, magasins, alertes, inventaires.\n\n" +
            "Cette action est IRRÉVERSIBLE.\n\nSauvegardez d'abord !"
        )) return;
        try {
            const prods = await Api.products();
            for (const p of prods) await Api.prodDel(p.id);
            await Api.mvClear();
            const whs = await Api.warehouses();
            for (const w of whs) await Api.whDel(w.id);
            toast('Toutes les données ont été supprimées', 'success');
            setTimeout(() => location.reload(), 1200);
        } catch (e) {
            toast(e.message || 'Erreur suppression totale', 'error');
        }
    },

    // ══════════════════════════════════════════════════════════════
    // LANGUE
    // ══════════════════════════════════════════════════════════════
    initLangGrid() {
        const grid = document.getElementById('langGrid');
        if (!grid) return;
        const I18N      = window.I18N      || {};
        const FLAGS     = I18N.FLAGS       || {};
        const NAMES     = I18N.NAMES       || {};
        const SUPPORTED = I18N.SUPPORTED   || ['fr', 'en'];
        const render = () => {
            const cur = window.SM_LANG || 'fr';
            grid.innerHTML = SUPPORTED.map(lang => `
                <button class="lang-card${lang === cur ? ' active' : ''}" data-lang="${lang}">
                    <span class="lang-card-flag">${FLAGS[lang] || '🌐'}</span>
                    <span class="lang-card-name">${NAMES[lang] || lang}</span>
                    <span class="lang-card-check">✓</span>
                </button>
            `).join('');
            grid.querySelectorAll('[data-lang]').forEach(btn => {
                btn.addEventListener('click', async () => {
                    const lang = btn.dataset.lang;
                    if (lang === window.SM_LANG) return;
                    grid.querySelectorAll('.lang-card').forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');
                    try {
                        await window.setLang(lang);
                        toast('Langue : ' + (NAMES[lang] || lang), 'success');
                        render();
                    } catch (e) {
                        toast('Erreur changement de langue', 'error');
                        render();
                    }
                });
            });
        };
        render();
    },

    // ══════════════════════════════════════════════════════════════
    // HELPERS
    // ══════════════════════════════════════════════════════════════
    _esc(s) {
        return String(s || '').replace(/[&<>"']/g, m =>
            ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' }[m]));
    },

    _fmtDate(iso) {
        if (!iso) return '—';
        try {
            const d = new Date(iso);
            return window.Locale ? window.Locale.formatDateTime(d) : d.toLocaleString();
        } catch { return iso; }
    },
};
