import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import Layout from '../components/Layout';
import { api } from '../lib/api';
import { toast } from 'sonner';
import { useAuth } from '../context/AuthContext';
import { Users, MessageSquareQuote, Plus, Trash2, UserPlus, X, Edit3, Send, Bell, Check, Shield, UserCog, KeyRound, Power, ChevronRight, Package, PenLine, Save, ImagePlus, Copy, Clock, AlertTriangle } from 'lucide-react';
import { UpdatesPanel } from './AdminUpdates';
import { XDockScriptsPanel } from './XDockScriptsAdmin';

function SignaturePanel() {
    const { user, refreshMe } = useAuth();
    const [signature, setSignature] = useState('');
    const [busy, setBusy] = useState(false);
    const [images, setImages] = useState([]);
    const [uploading, setUploading] = useState(false);
    const fileInputRef = React.useRef(null);
    const textareaRef = React.useRef(null);

    useEffect(() => {
        setSignature(user?.email_signature || '');
    }, [user?.email_signature]);

    const loadImages = async () => {
        try {
            const r = await api.get('/users/me/signature-images');
            setImages(r.data?.items || []);
        } catch (_e) { /* silencieux */ }
    };

    useEffect(() => { loadImages(); }, []);

    const save = async () => {
        setBusy(true);
        try {
            await api.put('/users/me/email-signature', { signature });
            if (typeof refreshMe === 'function') await refreshMe();
            toast.success('Signature enregistrée');
        } catch (e) {
            toast.error(e?.response?.data?.detail || 'Erreur');
        } finally { setBusy(false); }
    };

    const uploadImage = async (file) => {
        if (!file) return;
        if (file.size > 500 * 1024) {
            toast.error('Image trop lourde (500 KB max)');
            return;
        }
        setUploading(true);
        try {
            const form = new FormData();
            form.append('file', file);
            const r = await api.post('/users/me/signature-image', form, {
                headers: { 'Content-Type': 'multipart/form-data' },
            });
            const url = r.data?.url;
            if (!url) throw new Error('URL manquante');
            // Insère un lien texte à la position du curseur dans la signature
            const ta = textareaRef.current;
            const insertion = `\nLogo : ${url}\n`;
            if (ta) {
                const start = ta.selectionStart || signature.length;
                const end = ta.selectionEnd || signature.length;
                const next = signature.slice(0, start) + insertion + signature.slice(end);
                setSignature(next);
                setTimeout(() => {
                    ta.focus();
                    const pos = start + insertion.length;
                    ta.setSelectionRange(pos, pos);
                }, 0);
            } else {
                setSignature(signature + insertion);
            }
            await loadImages();
            toast.success('Image ajoutée — pense à enregistrer la signature');
        } catch (e) {
            toast.error(e?.response?.data?.detail || 'Erreur upload image');
        } finally {
            setUploading(false);
            if (fileInputRef.current) fileInputRef.current.value = '';
        }
    };

    const deleteImage = async (token) => {
        if (!window.confirm('Supprimer cette image ?')) return;
        try {
            await api.delete(`/users/me/signature-image/${token}`);
            await loadImages();
            toast.success('Image supprimée');
        } catch (e) {
            toast.error(e?.response?.data?.detail || 'Erreur');
        }
    };

    const copyUrl = async (url) => {
        try {
            await navigator.clipboard.writeText(url);
            toast.success('URL copiée');
        } catch (_e) {
            toast.error('Impossible de copier');
        }
    };

    return (
        <div className="max-w-3xl space-y-5">
            <div className="rounded-lg border border-slate-200 bg-white p-5 sm:p-6">
                <div className="flex items-start gap-3 mb-4">
                    <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-md bg-stef/10 text-stef">
                        <PenLine className="h-5 w-5" />
                    </div>
                    <div className="flex-1 min-w-0">
                        <h2 className="font-heading text-lg font-bold text-slate-900">Ma signature email</h2>
                        <p className="text-sm text-slate-500 mt-1">
                            Ajoutée automatiquement à la fin des emails envoyés depuis «&nbsp;<em>Envoyer par email</em>&nbsp;» dans un dossier camion.
                        </p>
                        <p className="text-[11px] text-amber-700 bg-amber-50 border border-amber-200 rounded px-2 py-1 mt-2 inline-block">
                            ⚠️ Les images apparaissent comme des liens cliquables dans Outlook (limitation du protocole <code className="font-mono">mailto:</code>).
                        </p>
                    </div>
                </div>

                <textarea
                    ref={textareaRef}
                    data-testid="signature-textarea"
                    value={signature}
                    onChange={(e) => setSignature(e.target.value)}
                    rows={8}
                    placeholder={"Cordialement,\nPrénom NOM\nFonction · STEF\n+33 6 12 34 56 78"}
                    className="w-full rounded-md border border-slate-300 px-3 py-2.5 text-sm text-slate-900 font-mono whitespace-pre focus:border-stef focus:outline-none focus:ring-2 focus:ring-stef/20"
                    maxLength={4000}
                />

                <div className="flex items-center justify-between mt-2 flex-wrap gap-2">
                    <p className="text-[11px] text-slate-400">
                        {signature.length}/4000 caractères
                    </p>
                    <div className="flex items-center gap-2">
                        <input
                            ref={fileInputRef}
                            type="file"
                            accept="image/png,image/jpeg,image/gif,image/webp"
                            className="hidden"
                            data-testid="signature-image-input"
                            onChange={(e) => uploadImage(e.target.files?.[0])}
                        />
                        <button
                            type="button"
                            data-testid="signature-image-btn"
                            onClick={() => fileInputRef.current?.click()}
                            disabled={uploading}
                            className="inline-flex items-center gap-2 rounded-md border border-slate-300 bg-white px-4 h-10 text-sm font-heading font-bold text-slate-700 hover:bg-slate-50 transition disabled:opacity-50"
                        >
                            <ImagePlus className="h-4 w-4" />
                            {uploading ? 'Upload…' : 'Ajouter une image'}
                        </button>
                        <button
                            type="button"
                            data-testid="signature-save-btn"
                            onClick={save}
                            disabled={busy || signature === (user?.email_signature || '')}
                            className="inline-flex items-center gap-2 rounded-md bg-stef text-white px-4 h-10 text-sm font-heading font-bold transition disabled:opacity-50 hover:bg-stef-hover"
                        >
                            <Save className="h-4 w-4" />
                            {busy ? 'Enregistrement…' : 'Enregistrer'}
                        </button>
                    </div>
                </div>
            </div>

            {images.length > 0 && (
                <div className="rounded-lg border border-slate-200 bg-white p-5 sm:p-6">
                    <h3 className="font-heading text-base font-bold text-slate-900 mb-3">Mes images uploadées ({images.length})</h3>
                    <div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
                        {images.map((img) => (
                            <div key={img.token} className="border border-slate-200 rounded-md overflow-hidden bg-slate-50 group relative">
                                <a href={img.url} target="_blank" rel="noopener noreferrer" className="block">
                                    <img src={img.url} alt={img.filename || 'sig'} className="w-full h-24 object-contain bg-white" />
                                </a>
                                <div className="px-2 py-1.5 flex items-center justify-between gap-1 text-[10px] text-slate-500 border-t border-slate-200 bg-white">
                                    <span className="truncate flex-1" title={img.filename}>{img.filename || '—'}</span>
                                    <button
                                        type="button"
                                        onClick={() => copyUrl(img.url)}
                                        className="p-1 text-slate-400 hover:text-stef transition"
                                        title="Copier l'URL"
                                    >
                                        <Copy className="h-3 w-3" />
                                    </button>
                                    <button
                                        type="button"
                                        onClick={() => deleteImage(img.token)}
                                        className="p-1 text-slate-400 hover:text-red-600 transition"
                                        title="Supprimer"
                                    >
                                        <Trash2 className="h-3 w-3" />
                                    </button>
                                </div>
                            </div>
                        ))}
                    </div>
                </div>
            )}
        </div>
    );
}

function buildUsername(fullname) {
    const parts = (fullname || '').trim().toLowerCase().split(/\s+/).filter(Boolean);
    if (parts.length < 2) return parts.join('');
    const first = parts[0];
    const lastInitial = parts[parts.length - 1][0];
    return `${first}.${lastInitial}`;
}

const isGpv3Native = (u) => !!u && (u.gp_role === 'admin' || (u.gp_role && !['cariste', 'bureau'].includes(u.gp_role)));

function UserModal({ open, onClose, onSaved, initial }) {
    const { user: me } = useAuth();
    const isSuperAdmin = (me?.username || '').toLowerCase() === 'mathieu.u';
    const isEdit = !!initial;
    const editingGpv3 = isEdit && isGpv3Native(initial);
    const [form, setForm] = useState({ username: '', fullname: '', password: '', role: 'cariste', mytruckRole: 'cariste', mustChangePassword: true, email: '', emailXdock: '', serviceShift: '', xdockName: '', canManageXdockScripts: false });
    const [autoUsername, setAutoUsername] = useState(true);
    const [loading, setLoading] = useState(false);

    useEffect(() => {
        if (open) {
            setForm({
                username: initial?.username || '',
                fullname: initial?.fullname || '',
                password: '',
                role: initial?.role || 'cariste',
                mytruckRole: initial?.mytruck_role || initial?.role || 'cariste',
                mustChangePassword: isEdit ? !!initial?.must_change_password : true,
                email: initial?.email || '',
                emailXdock: initial?.email_xdock || '',
                serviceShift: initial?.service_shift || '',
                xdockName: initial?.xdock_name || '',
                canManageXdockScripts: !!initial?.can_manage_xdock_scripts,
                canManageFolderEmail: !!initial?.can_manage_folder_email,
            });
            setAutoUsername(!isEdit);
        }
    }, [open, initial, isEdit]);

    if (!open) return null;

    const onFullnameChange = (v) => {
        setForm((f) => ({
            ...f,
            fullname: v,
            username: autoUsername ? buildUsername(v) : f.username,
        }));
    };

    const onUsernameChange = (v) => {
        setAutoUsername(false);
        setForm({ ...form, username: v.toLowerCase().replace(/[^a-z0-9._-]/g, '') });
    };

    const onPwdChange = (v) => {
        setForm({ ...form, password: v.replace(/\D/g, '').slice(0, 6) });
    };

    const submit = async (e) => {
        e.preventDefault();
        if (!form.username.trim()) { toast.error('Identifiant requis'); return; }
        if (!isEdit && !/^\d{6}$/.test(form.password)) { toast.error('Code à 6 chiffres requis'); return; }
        if (isEdit && form.password && !/^\d{6}$/.test(form.password)) { toast.error('Code à 6 chiffres'); return; }
        setLoading(true);
        try {
            if (isEdit) {
                const payload = {
                    username: form.username,
                    fullname: form.fullname,
                    email: (form.email || '').trim(),
                    email_xdock: (form.emailXdock || '').trim(),
                    service_shift: (form.serviceShift || '').trim(),
                    xdock_name: (form.xdockName || '').trim(),
                };
                if (editingGpv3) {
                    payload.mytruck_role = form.mytruckRole;
                } else {
                    payload.role = form.role;
                }
                if (form.password) payload.password = form.password;
                // Always include must_change_password so the bureau can toggle it
                payload.must_change_password = form.mustChangePassword;
                // Super-admin only: peut accorder le droit "gérer scripts XDock+"
                if (isSuperAdmin) {
                    payload.can_manage_xdock_scripts = !!form.canManageXdockScripts;
                    payload.can_manage_folder_email = !!form.canManageFolderEmail;
                }
                await api.patch(`/users/${initial.id}`, payload);
                toast.success('Utilisateur mis à jour');
            } else {
                await api.post('/users', {
                    username: form.username,
                    fullname: form.fullname,
                    password: form.password,
                    role: form.role,
                    email: (form.email || '').trim(),
                    email_xdock: (form.emailXdock || '').trim(),
                    service_shift: (form.serviceShift || '').trim(),
                    xdock_name: (form.xdockName || '').trim(),
                });
                toast.success('Utilisateur créé');
            }
            onSaved();
            onClose();
        } catch (err) {
            toast.error(err?.response?.data?.detail || 'Erreur');
        } finally { setLoading(false); }
    };

    const currentRole = editingGpv3 ? form.mytruckRole : form.role;
    const setCurrentRole = (r) => editingGpv3 ? setForm({ ...form, mytruckRole: r }) : setForm({ ...form, role: r });

    return (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-3 sm:p-4" onClick={onClose}>
            <form onClick={(e) => e.stopPropagation()} onSubmit={submit} className="w-full max-w-md rounded-xl bg-white shadow-2xl overflow-hidden flex flex-col max-h-[92vh]" data-testid={isEdit ? 'edit-user-modal' : 'create-user-modal'}>
                {/* Header */}
                <div className="flex items-center justify-between px-5 sm:px-6 py-4 border-b border-slate-100 bg-gradient-to-br from-white to-slate-50">
                    <div>
                        <p className="text-[10px] font-bold uppercase tracking-[0.2em] text-stef/80">{isEdit ? 'Édition' : 'Nouveau'}</p>
                        <h3 className="mt-0.5 font-heading text-xl font-black tracking-tight text-slate-900">{isEdit ? form.fullname || form.username : 'Nouvel utilisateur'}</h3>
                    </div>
                    <button type="button" onClick={onClose} className="h-9 w-9 rounded-full hover:bg-slate-100 flex items-center justify-center text-slate-500 transition">
                        <X className="h-5 w-5" />
                    </button>
                </div>

                {/* Body */}
                <div className="px-5 sm:px-6 py-5 space-y-5 overflow-y-auto">
                    {/* Section identité */}
                    <section className="space-y-3">
                        <div className="flex items-center gap-2">
                            <div className="h-5 w-1 rounded-full bg-stef" />
                            <h4 className="text-[11px] font-bold uppercase tracking-wider text-slate-700">Identité</h4>
                        </div>
                        <div>
                            <label className="text-xs font-bold uppercase tracking-wider text-slate-600">Nom complet</label>
                            <input data-testid="cu-fullname" value={form.fullname} onChange={(e) => onFullnameChange(e.target.value)} placeholder="Jean Dupuis" disabled={editingGpv3} className="mt-1 w-full h-11 rounded-md border border-slate-300 px-3 focus:border-stef focus:ring-2 focus:ring-stef/20 outline-none transition disabled:bg-slate-50 disabled:text-slate-500" />
                        </div>
                        <div>
                            <label className="text-xs font-bold uppercase tracking-wider text-slate-600">Identifiant (prénom.x)</label>
                            <input data-testid="cu-username" value={form.username} onChange={(e) => onUsernameChange(e.target.value)} placeholder="Jean.D" disabled={editingGpv3} className="mt-1 w-full h-11 rounded-md border border-slate-300 px-3 focus:border-stef focus:ring-2 focus:ring-stef/20 outline-none transition font-mono disabled:bg-slate-50 disabled:text-slate-500" />
                            {!editingGpv3 && <p className="mt-1 text-[11px] text-slate-500">Auto-généré depuis le nom complet. Modifiable.</p>}
                        </div>
                        {/* Code à 6 chiffres — visible pour tous, y compris utilisateurs GP V3 (changement propagé dans la DB partagée) */}
                        <div>
                            <label className="text-xs font-bold uppercase tracking-wider text-slate-600">
                                Code à 6 chiffres {isEdit ? '(laisser vide pour ne pas changer)' : '*'}
                            </label>
                            <input
                                data-testid="cu-password"
                                type="text"
                                inputMode="numeric"
                                value={form.password}
                                onChange={(e) => onPwdChange(e.target.value)}
                                placeholder={isEdit ? '••••••' : '6 chiffres'}
                                maxLength={6}
                                className="mt-1 w-full h-11 rounded-md border border-slate-300 px-3 focus:border-stef focus:ring-2 focus:ring-stef/20 outline-none transition tracking-[0.4em] text-center font-mono"
                            />
                            {!isEdit && <p className="mt-1 text-[11px] text-slate-500">L&apos;utilisateur devra changer ce code à sa première connexion.</p>}
                        </div>
                        {isEdit && (
                            <label className="flex items-start gap-2.5 cursor-pointer select-none rounded-md hover:bg-slate-50 p-2 -mx-2 transition" data-testid="cu-must-change-label">
                                <input
                                    data-testid="cu-must-change-password"
                                    type="checkbox"
                                    checked={form.mustChangePassword}
                                    onChange={(e) => setForm({ ...form, mustChangePassword: e.target.checked })}
                                    className="mt-0.5 h-4 w-4 rounded border-slate-300 text-stef focus:ring-stef"
                                />
                                <span className="text-xs text-slate-700">
                                    <strong>Forcer le changement de code</strong> à la prochaine connexion
                                    <span className="block text-[11px] text-slate-500 mt-0.5">À cocher quand tu lui donnes un nouveau code temporaire.</span>
                                </span>
                            </label>
                        )}
                    </section>

                    {/* Section Rôle + Équipe */}
                    <section className="space-y-3">
                        <div className="flex items-center gap-2">
                            <div className="h-5 w-1 rounded-full bg-stef" />
                            <h4 className="text-[11px] font-bold uppercase tracking-wider text-slate-700">Rôle &amp; équipe</h4>
                        </div>
                        <div>
                            <label className="text-xs font-bold uppercase tracking-wider text-slate-600">
                                {editingGpv3 ? 'Rôle My Truck' : 'Rôle'}
                            </label>
                            <div className="mt-1 grid grid-cols-2 gap-2">
                                {['cariste', 'bureau'].map((r) => (
                                    <button
                                        key={r}
                                        type="button"
                                        data-testid={`cu-role-${r}`}
                                        onClick={() => setCurrentRole(r)}
                                        className={`h-11 rounded-md border-2 font-heading font-bold uppercase tracking-wider text-sm transition active:scale-[0.98] ${
                                            currentRole === r ? 'bg-stef text-white border-stef shadow-md shadow-stef/20' : 'bg-white text-slate-700 border-slate-200 hover:border-stef/50 hover:bg-slate-50'
                                        }`}
                                    >{r}</button>
                                ))}
                            </div>
                            <div className={`mt-2 rounded-md px-3 py-2 text-[11px] leading-relaxed transition ${currentRole === 'bureau' ? 'bg-emerald-50 border border-emerald-200 text-emerald-800' : 'bg-slate-50 border border-slate-200 text-slate-600'}`}>
                                <strong>Accès Gestion Palettes :</strong>{' '}
                                {currentRole === 'bureau' ? (
                                    <span className="font-bold">✓ Oui — Reliquats &amp; Retours fournisseurs</span>
                                ) : (
                                    <span className="font-bold">✗ Non — Seul My Truck</span>
                                )}
                            </div>
                        </div>

                        <div>
                            <label className="text-xs font-bold uppercase tracking-wider text-slate-600">Équipe</label>
                            <div className="mt-1 grid grid-cols-2 sm:grid-cols-4 gap-1.5">
                                {[
                                    { v: '', l: 'Aucune' },
                                    { v: 'MATIN', l: 'Matin' },
                                    { v: 'APRES_MIDI', l: 'Après-midi' },
                                    { v: 'NUIT', l: 'Nuit' },
                                ].map((opt) => (
                                    <button
                                        key={opt.v || 'none'}
                                        type="button"
                                        data-testid={`cu-shift-${opt.v || 'none'}`}
                                        onClick={() => setForm({ ...form, serviceShift: opt.v })}
                                        className={`h-10 rounded-md border-2 text-xs font-heading font-bold uppercase tracking-wider transition active:scale-[0.98] ${
                                            form.serviceShift === opt.v ? 'bg-amber-500 text-white border-amber-500 shadow-sm' : 'bg-white text-slate-700 border-slate-200 hover:border-amber-400 hover:bg-amber-50/50'
                                        }`}
                                    >{opt.l}</button>
                                ))}
                            </div>
                        </div>
                    </section>

                    {/* Section Emails */}
                    <section className="space-y-3">
                        <div className="flex items-center gap-2">
                            <div className="h-5 w-1 rounded-full bg-stef" />
                            <h4 className="text-[11px] font-bold uppercase tracking-wider text-slate-700">Adresses email (facultatif)</h4>
                        </div>
                        <div>
                            <label className="text-xs font-bold uppercase tracking-wider text-slate-600">Email</label>
                            <input
                                data-testid="cu-email"
                                type="email"
                                value={form.email}
                                onChange={(e) => setForm({ ...form, email: e.target.value })}
                                placeholder="Mon.Email@gp-eff.fr"
                                className="mt-1 w-full h-11 rounded-md border border-slate-300 bg-white px-3 text-sm focus:border-stef focus:ring-2 focus:ring-stef/20 outline-none transition"
                            />
                        </div>
                        <div>
                            <label className="text-xs font-bold uppercase tracking-wider text-slate-600">Email XDOCK</label>
                            <input
                                data-testid="cu-xdock-email"
                                type="email"
                                value={form.emailXdock}
                                onChange={(e) => setForm({ ...form, emailXdock: e.target.value })}
                                placeholder="STB_XxXx@xdock.de"
                                className="mt-1 w-full h-11 rounded-md border border-slate-300 bg-white px-3 text-sm focus:border-stef focus:ring-2 focus:ring-stef/20 outline-none transition"
                            />
                        </div>
                    </section>

                    {/* Section XDock Plus (extension Edge) */}
                    <section className="space-y-3">
                        <div className="flex items-center gap-2">
                            <div className="h-5 w-1 rounded-full bg-stef" />
                            <h4 className="text-[11px] font-bold uppercase tracking-wider text-slate-700">XDock Plus (extension Edge)</h4>
                        </div>
                        <p className="text-xs text-slate-500 -mt-1">
                            Nom d'utilisateur XDock — sert au pré-remplissage automatique (plaque tracteur, remorque, n° tournée, type EM/SM) à la création d'un dossier. L'extension Edge XDock Plus doit être installée sur le poste.
                        </p>
                        <div>
                            <label className="text-xs font-bold uppercase tracking-wider text-slate-600">Utilisateur XDock</label>
                            <input
                                data-testid="cu-xdock-name"
                                type="text"
                                value={form.xdockName}
                                onChange={(e) => setForm({ ...form, xdockName: e.target.value })}
                                placeholder="Jean"
                                className="mt-1 w-full h-11 rounded-md border border-slate-300 bg-white px-3 text-sm focus:border-stef focus:ring-2 focus:ring-stef/20 outline-none transition"
                            />
                        </div>
                    </section>
                </div>

                {/* Footer */}
                <div className="px-5 sm:px-6 py-3 border-t border-slate-100 bg-slate-50/50 flex justify-end gap-2">
                    <button type="button" onClick={onClose} className="h-10 rounded-md border border-slate-300 bg-white px-4 text-sm font-bold text-slate-700 hover:bg-slate-50 active:scale-[0.99] transition">Annuler</button>
                    <button data-testid="cu-submit" type="submit" disabled={loading} className="h-10 rounded-md bg-stef px-5 text-sm font-heading font-bold text-white hover:bg-stef-hover active:scale-[0.99] transition disabled:opacity-60 shadow-md shadow-stef/20">
                        {loading ? '…' : (isEdit ? 'Enregistrer' : 'Créer')}
                    </button>
                </div>
            </form>
        </div>
    );
}

function GrantAccessModal({ open, onClose, onSaved }) {
    const [users, setUsers] = useState([]);
    const [loading, setLoading] = useState(false);
    const [pickingRole, setPickingRole] = useState(null); // {user, role}

    useEffect(() => {
        if (!open) return;
        api.get('/users', { params: { grantable: 1 } }).then(r => {
            // Only show users without My Truck access right now
            setUsers(r.data.filter((u) => !u.role));
        });
    }, [open]);

    if (!open) return null;

    const grant = async (user, role) => {
        setLoading(true);
        try {
            await api.patch(`/users/${user.id}`, { mytruck_role: role });
            toast.success(`Accès ${role} accordé à ${user.fullname || user.username}`);
            onSaved();
            onClose();
        } catch (err) {
            toast.error(err?.response?.data?.detail || 'Erreur');
        } finally { setLoading(false); setPickingRole(null); }
    };

    return (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-3 sm:p-4" onClick={onClose}>
            <div onClick={(e) => e.stopPropagation()} className="w-full max-w-md rounded-lg bg-white p-5 sm:p-6 shadow-xl" data-testid="grant-access-modal">
                <div className="flex items-center justify-between mb-4">
                    <div>
                        <h3 className="font-heading text-xl font-black text-slate-900">Donner accès à My Truck</h3>
                        <p className="text-xs text-slate-500 mt-0.5">Choisis un compte GP v3 et son rôle My Truck.</p>
                    </div>
                    <button type="button" onClick={onClose}><X className="h-5 w-5 text-slate-400" /></button>
                </div>

                {users.length === 0 ? (
                    <p className="text-sm text-slate-400 italic py-6 text-center">Tous les comptes ont déjà accès à My Truck.</p>
                ) : (
                    <div className="divide-y divide-slate-100 max-h-80 overflow-y-auto -mx-2">
                        {users.map((u) => (
                            <div key={u.id} className="px-2 py-3" data-testid={`grant-row-${u.id}`}>
                                <div className="flex items-center justify-between gap-3">
                                    <div className="min-w-0">
                                        <p className="font-heading font-bold text-sm text-slate-900 truncate">{u.fullname || u.username}</p>
                                        <p className="text-[11px] text-slate-500 font-mono truncate">{u.username} · {u.gp_role}</p>
                                    </div>
                                    {pickingRole?.user?.id === u.id ? (
                                        <div className="flex gap-1.5 shrink-0">
                                            <button disabled={loading} onClick={() => grant(u, 'cariste')} className="h-9 rounded-md bg-amber-500 text-white px-3 text-xs font-heading font-bold uppercase tracking-wider hover:bg-amber-600">Cariste</button>
                                            <button disabled={loading} onClick={() => grant(u, 'bureau')} className="h-9 rounded-md bg-stef text-white px-3 text-xs font-heading font-bold uppercase tracking-wider hover:bg-stef-hover">Bureau</button>
                                            <button disabled={loading} onClick={() => setPickingRole(null)} className="h-9 w-9 rounded-md border border-slate-300 text-slate-500 hover:bg-slate-50 flex items-center justify-center"><X className="h-4 w-4" /></button>
                                        </div>
                                    ) : (
                                        <button data-testid={`grant-btn-${u.id}`} onClick={() => setPickingRole({ user: u })} className="h-9 rounded-md bg-stef text-white px-3 text-xs font-heading font-bold uppercase tracking-wider hover:bg-stef-hover shrink-0 inline-flex items-center gap-1.5">
                                            <Plus className="h-3.5 w-3.5" /> Donner accès
                                        </button>
                                    )}
                                </div>
                            </div>
                        ))}
                    </div>
                )}

                <div className="mt-4 flex justify-end">
                    <button type="button" onClick={onClose} className="h-10 rounded-md border border-slate-300 px-4 text-sm font-semibold text-slate-700 hover:bg-slate-50">Fermer</button>
                </div>
            </div>
        </div>
    );
}

function UsersPanel() {
    const [users, setUsers] = useState([]);
    const [open, setOpen] = useState(false);
    const [grantOpen, setGrantOpen] = useState(false);
    const [editing, setEditing] = useState(null);
    const [filter, setFilter] = useState('all');

    const load = () => api.get('/users').then(r => setUsers(r.data));
    useEffect(() => { load(); }, []);

    const remove = async (u) => {
        const label = isGpv3Native(u)
            ? `Retirer l'accès My Truck à ${u.fullname || u.username} ? Son compte GP reste intact.`
            : `Supprimer définitivement ${u.fullname || u.username} ?`;
        if (!window.confirm(label)) return;
        try {
            const r = await api.delete(`/users/${u.id}`);
            toast.success(r.data?.action === 'revoked' ? 'Accès My Truck retiré' : 'Supprimé');
            load();
        } catch (err) {
            toast.error(err?.response?.data?.detail || 'Erreur');
        }
    };

    const filtered = users
        .filter((u) => filter === 'all' ? true : u.role === filter)
        .sort((a, b) => {
            if (a.role !== b.role) return a.role === 'bureau' ? -1 : 1;
            return (a.username || '').localeCompare(b.username || '');
        });

    const counts = {
        all: users.length,
        bureau: users.filter((u) => u.role === 'bureau').length,
        cariste: users.filter((u) => u.role === 'cariste').length,
    };

    return (
        <div>
            <div className="flex items-start justify-between mb-4 gap-3 flex-wrap">
                <div>
                    <h2 className="font-heading text-xl sm:text-2xl font-black text-slate-900">Utilisateurs</h2>
                    <p className="text-sm text-slate-500">Crée des comptes, ou donne accès à My Truck à des admins GP.</p>
                </div>
                <div className="flex items-center gap-2 flex-wrap">
                    <button data-testid="open-grant-access" onClick={() => setGrantOpen(true)} className="inline-flex items-center gap-2 rounded-md border border-stef text-stef px-4 h-11 text-sm font-heading font-bold hover:bg-stef/5 transition-all">
                        <Shield className="h-4 w-4" /> <span className="hidden sm:inline">Donner accès</span><span className="sm:hidden">Accès</span>
                    </button>
                    <button data-testid="open-create-user" onClick={() => { setEditing(null); setOpen(true); }} className="inline-flex items-center gap-2 rounded-md bg-stef px-4 h-11 text-sm font-heading font-bold text-white hover:bg-stef-hover transition-all">
                        <UserPlus className="h-4 w-4" /> <span className="hidden sm:inline">Nouvel utilisateur</span><span className="sm:hidden">Nouveau</span>
                    </button>
                </div>
            </div>

            <div className="mb-4 flex items-center gap-2 flex-wrap" data-testid="role-filter">
                {[
                    { id: 'all', label: 'Tous' },
                    { id: 'bureau', label: 'Bureau' },
                    { id: 'cariste', label: 'Caristes' },
                ].map((f) => (
                    <button
                        key={f.id}
                        data-testid={`filter-${f.id}`}
                        onClick={() => setFilter(f.id)}
                        className={`inline-flex items-center gap-2 rounded-full border px-3.5 h-9 text-xs font-heading font-bold uppercase tracking-wider transition ${
                            filter === f.id
                                ? 'bg-stef text-white border-stef'
                                : 'bg-white text-slate-700 border-slate-300 hover:border-stef hover:text-stef'
                        }`}
                    >
                        {f.label}
                        <span className={`inline-flex items-center justify-center rounded-full px-1.5 h-5 text-[10px] font-bold ${
                            filter === f.id ? 'bg-white/20 text-white' : 'bg-slate-100 text-slate-600'
                        }`}>{counts[f.id]}</span>
                    </button>
                ))}
            </div>

            <div className="md:hidden space-y-2" data-testid="users-list-mobile">
                {filtered.length === 0 && <p className="text-sm text-slate-400 italic py-4 text-center">Aucun utilisateur</p>}
                {filtered.map((u) => (
                    <div key={u.id} className="rounded-lg border border-slate-200 bg-white p-4" data-testid={`user-row-${u.id}`}>
                        <div className="flex items-start justify-between gap-2">
                            <div className="min-w-0">
                                <p className="font-heading font-bold text-slate-900 truncate">{u.fullname || u.username}</p>
                                <p className="text-xs text-slate-500 font-mono truncate">{u.username}</p>
                                <div className="mt-1 flex items-center gap-1.5 flex-wrap">
                                    <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-bold uppercase tracking-wider ${u.role === 'bureau' ? 'bg-stef/10 text-stef' : 'bg-amber-50 text-amber-700'}`}>{u.role}</span>
                                    {u.service_shift && (
                                        <span className="inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider bg-sky-50 text-sky-700">
                                            {u.service_shift === 'MATIN' ? 'Matin' : u.service_shift === 'APRES_MIDI' ? 'Après-midi' : u.service_shift === 'NUIT' ? 'Nuit' : u.service_shift === 'JOURNEE' ? 'Journée' : u.service_shift}
                                        </span>
                                    )}
                                    {isGpv3Native(u) && (
                                        <span className="inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider bg-violet-50 text-violet-700"><Shield className="h-2.5 w-2.5" />GP</span>
                                    )}
                                    {u.must_change_password && <span className="inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider bg-rose-50 text-rose-700">À changer</span>}
                                </div>
                            </div>
                            <div className="flex items-center gap-1 shrink-0">
                                <button data-testid={`edit-user-${u.id}`} onClick={() => { setEditing(u); setOpen(true); }} className="h-9 w-9 rounded-md text-stef hover:bg-stef/10 flex items-center justify-center"><Edit3 className="h-4 w-4" /></button>
                                <button data-testid={`delete-user-${u.id}`} onClick={() => remove(u)} className="h-9 w-9 rounded-md text-red-600 hover:bg-red-50 flex items-center justify-center" title={isGpv3Native(u) ? 'Retirer accès My Truck' : 'Supprimer'}>
                                    {isGpv3Native(u) ? <UserCog className="h-4 w-4" /> : <Trash2 className="h-4 w-4" />}
                                </button>
                            </div>
                        </div>
                    </div>
                ))}
            </div>

            <div className="hidden md:block rounded-lg border border-slate-200 bg-white overflow-hidden">
                <table className="w-full text-sm" data-testid="users-table">
                    <thead className="bg-slate-50 text-xs uppercase tracking-wider text-slate-500">
                        <tr>
                            <th className="text-left px-4 py-3 font-bold">Nom complet</th>
                            <th className="text-left px-4 py-3 font-bold">Identifiant</th>
                            <th className="text-left px-4 py-3 font-bold">Rôle My Truck</th>
                            <th className="text-left px-4 py-3 font-bold">Origine</th>
                            <th className="text-left px-4 py-3 font-bold">Statut</th>
                            <th className="text-right px-4 py-3 font-bold">Actions</th>
                        </tr>
                    </thead>
                    <tbody className="divide-y divide-slate-100">
                        {filtered.length === 0 && (
                            <tr><td colSpan={6} className="px-4 py-8 text-center text-sm text-slate-400 italic">Aucun utilisateur</td></tr>
                        )}
                        {filtered.map((u) => (
                            <tr key={u.id} className="hover:bg-slate-50 transition" data-testid={`user-row-${u.id}-desktop`}>
                                <td className="px-4 py-3 font-heading font-bold text-slate-900">{u.fullname || '—'}</td>
                                <td className="px-4 py-3 font-mono text-slate-700">{u.username}</td>
                                <td className="px-4 py-3">
                                    <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-bold uppercase tracking-wider ${u.role === 'bureau' ? 'bg-stef/10 text-stef' : 'bg-amber-50 text-amber-700'}`}>{u.role}</span>
                                    {u.role === 'bureau' && (
                                        <span className="ml-1.5 inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider bg-emerald-50 text-emerald-700" title="Accès Gestion Palettes">
                                            <Shield className="h-2.5 w-2.5" /> GP
                                        </span>
                                    )}
                                </td>
                                <td className="px-4 py-3">
                                    {isGpv3Native(u) ? (
                                        <span className="inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider bg-violet-50 text-violet-700"><Shield className="h-2.5 w-2.5" /> GP — {u.gp_role}</span>
                                    ) : (
                                        <span className="text-[11px] text-slate-500">My Truck</span>
                                    )}
                                </td>
                                <td className="px-4 py-3">
                                    {u.must_change_password ? (
                                        <span className="inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider bg-rose-50 text-rose-700">Code à changer</span>
                                    ) : (
                                        <span className="inline-flex items-center gap-1 text-emerald-700 text-xs"><Check className="h-3 w-3" /> Actif</span>
                                    )}
                                </td>
                                <td className="px-4 py-3 text-right">
                                    <div className="inline-flex items-center gap-1">
                                        <button data-testid={`edit-user-${u.id}-desktop`} onClick={() => { setEditing(u); setOpen(true); }} className="inline-flex items-center gap-1 text-stef hover:text-stef-hover text-xs font-bold px-2 py-1 rounded hover:bg-stef/5">
                                            <Edit3 className="h-3.5 w-3.5" /> Modifier
                                        </button>
                                        <button data-testid={`delete-user-${u.id}-desktop`} onClick={() => remove(u)} className="inline-flex items-center gap-1 text-red-600 hover:text-red-700 text-xs font-bold px-2 py-1 rounded hover:bg-red-50">
                                            {isGpv3Native(u) ? <><UserCog className="h-3.5 w-3.5" /> Retirer accès</> : <><Trash2 className="h-3.5 w-3.5" /> Supprimer</>}
                                        </button>
                                    </div>
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>

            <UserModal open={open} onClose={() => setOpen(false)} onSaved={load} initial={editing} />
            <GrantAccessModal open={grantOpen} onClose={() => setGrantOpen(false)} onSaved={load} />
        </div>
    );
}

function PhrasesPanel() {
    const [phrases, setPhrases] = useState([]);
    const [text, setText] = useState('');

    const load = () => api.get('/phrases').then(r => setPhrases(r.data));
    useEffect(() => { load(); }, []);

    const add = async (e) => {
        e.preventDefault();
        if (!text.trim()) return;
        try {
            await api.post('/phrases', { text });
            setText('');
            load();
        } catch (err) {
            toast.error(err?.response?.data?.detail || 'Erreur');
        }
    };
    const remove = async (id) => {
        await api.delete(`/phrases/${id}`);
        load();
    };

    return (
        <div>
            <div className="mb-4">
                <h2 className="font-heading text-xl sm:text-2xl font-black text-slate-900">Phrases prédéfinies</h2>
                <p className="text-sm text-slate-500">Phrases rapides proposées aux caristes.</p>
            </div>

            <form onSubmit={add} className="rounded-lg border border-slate-200 bg-white p-4 sm:p-5 mb-4 flex items-center gap-3 flex-wrap sm:flex-nowrap" data-testid="add-phrase-form">
                <input
                    data-testid="phrase-text-input"
                    value={text}
                    onChange={(e) => setText(e.target.value)}
                    placeholder="Ex : La palette n'apparaît pas sur la tablette"
                    className="flex-1 min-w-0 h-11 rounded-md border border-slate-300 px-3 focus:border-stef focus:ring-2 focus:ring-stef/20 outline-none"
                />
                <button data-testid="add-phrase-btn" type="submit" className="inline-flex items-center gap-2 rounded-md bg-stef px-4 h-11 text-sm font-heading font-bold text-white hover:bg-stef-hover transition-all w-full sm:w-auto justify-center">
                    <Plus className="h-4 w-4" /> Ajouter
                </button>
            </form>

            <div className="rounded-lg border border-slate-200 bg-white p-4 sm:p-5">
                {phrases.length === 0 ? (
                    <p className="text-sm text-slate-400 italic">Aucune phrase configurée</p>
                ) : (
                    <ul className="divide-y divide-slate-100" data-testid="phrases-table">
                        {phrases.map((p) => (
                            <li key={p.id} className="flex items-center justify-between py-3 gap-3" data-testid={`phrase-row-${p.id}`}>
                                <span className="text-sm text-slate-800 truncate">{p.text}</span>
                                <button data-testid={`delete-phrase-${p.id}`} onClick={() => remove(p.id)} className="text-red-600 hover:text-red-700 text-xs font-bold inline-flex items-center gap-1 shrink-0">
                                    <Trash2 className="h-3.5 w-3.5" /> Supprimer
                                </button>
                            </li>
                        ))}
                    </ul>
                )}
            </div>
        </div>
    );
}

function NotificationsPanel() {
    const { user } = useAuth();
    const [users, setUsers] = useState([]);
    const [selectedIds, setSelectedIds] = useState([]);
    const [title, setTitle] = useState('');
    const [body, setBody] = useState('');
    const [sending, setSending] = useState(false);
    const [history, setHistory] = useState([]);
    const [filterRole, setFilterRole] = useState('cariste');

    const loadUsers = () => api.get('/users').then(r => setUsers(r.data.filter(u => u.id !== user.id)));
    const loadHistory = () => api.get('/notifications/history').then(r => setHistory(r.data)).catch(() => {});

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

    const filteredUsers = users.filter(u => filterRole === 'all' ? true : u.role === filterRole);

    const toggle = (id) => {
        setSelectedIds((s) => s.includes(id) ? s.filter(x => x !== id) : [...s, id]);
    };

    const toggleAll = () => {
        const ids = filteredUsers.map(u => u.id);
        const allSelected = ids.every(id => selectedIds.includes(id));
        if (allSelected) {
            setSelectedIds((s) => s.filter(id => !ids.includes(id)));
        } else {
            setSelectedIds((s) => Array.from(new Set([...s, ...ids])));
        }
    };

    const send = async (e) => {
        e.preventDefault();
        if (!title.trim()) { toast.error('Titre requis'); return; }
        if (!body.trim()) { toast.error('Message requis'); return; }
        if (selectedIds.length === 0) { toast.error('Sélectionnez au moins une personne'); return; }
        setSending(true);
        try {
            const r = await api.post('/notifications/send', {
                user_ids: selectedIds,
                title: title.trim(),
                body: body.trim(),
            });
            toast.success(`Envoyé à ${r.data.recipients} personne(s)`);
            setTitle('');
            setBody('');
            setSelectedIds([]);
            loadHistory();
        } catch (err) {
            toast.error(err?.response?.data?.detail || 'Erreur');
        } finally { setSending(false); }
    };

    const visibleIds = filteredUsers.map(u => u.id);
    const allSelected = visibleIds.length > 0 && visibleIds.every(id => selectedIds.includes(id));

    return (
        <div>
            <div className="mb-4">
                <h2 className="font-heading text-xl sm:text-2xl font-black text-slate-900">Envoyer une notification</h2>
                <p className="text-sm text-slate-500">Envoie un message instantané aux caristes (ou au bureau).</p>
            </div>

            <form onSubmit={send} className="rounded-lg border border-slate-200 bg-white p-4 sm:p-5 space-y-4" data-testid="send-notif-form">
                <div>
                    <label className="text-xs font-bold uppercase tracking-wider text-slate-700">Titre *</label>
                    <input
                        data-testid="notif-title"
                        value={title}
                        onChange={(e) => setTitle(e.target.value)}
                        placeholder="Ex : Pause déjeuner à 12h30"
                        maxLength={120}
                        className="mt-1 w-full h-11 rounded-md border border-slate-300 px-3 focus:border-stef focus:ring-2 focus:ring-stef/20 outline-none"
                    />
                </div>
                <div>
                    <label className="text-xs font-bold uppercase tracking-wider text-slate-700">Message *</label>
                    <textarea
                        data-testid="notif-body"
                        value={body}
                        onChange={(e) => setBody(e.target.value)}
                        rows={3}
                        placeholder="Le détail du message…"
                        className="mt-1 w-full rounded-md border border-slate-300 px-3 py-2 focus:border-stef focus:ring-2 focus:ring-stef/20 outline-none resize-y"
                    />
                </div>

                <div>
                    <div className="flex items-center justify-between gap-2 mb-2 flex-wrap">
                        <label className="text-xs font-bold uppercase tracking-wider text-slate-700">Destinataires ({selectedIds.length})</label>
                        <div className="flex items-center gap-2">
                            {['cariste', 'bureau', 'all'].map((r) => (
                                <button
                                    type="button"
                                    key={r}
                                    onClick={() => setFilterRole(r)}
                                    className={`inline-flex items-center gap-1 rounded-full border px-3 h-7 text-[11px] font-bold uppercase tracking-wider ${
                                        filterRole === r ? 'bg-stef text-white border-stef' : 'bg-white text-slate-600 border-slate-300 hover:border-stef'
                                    }`}
                                >{r === 'all' ? 'Tous' : r === 'cariste' ? 'Caristes' : 'Bureau'}</button>
                            ))}
                            <button
                                type="button"
                                onClick={toggleAll}
                                data-testid="notif-toggle-all"
                                className="text-xs font-bold text-stef hover:text-stef-hover"
                            >{allSelected ? 'Tout désélectionner' : 'Tout sélectionner'}</button>
                        </div>
                    </div>
                    <div className="rounded-md border border-slate-200 divide-y divide-slate-100 max-h-72 overflow-y-auto" data-testid="notif-recipients">
                        {filteredUsers.length === 0 && <p className="px-3 py-4 text-sm text-slate-400 italic text-center">Aucun utilisateur</p>}
                        {filteredUsers.map((u) => {
                            const sel = selectedIds.includes(u.id);
                            return (
                                <label key={u.id} className="flex items-center gap-3 px-3 py-2.5 cursor-pointer hover:bg-slate-50" data-testid={`notif-user-${u.id}`}>
                                    <input
                                        type="checkbox"
                                        checked={sel}
                                        onChange={() => toggle(u.id)}
                                        className="h-4 w-4 rounded border-slate-300 text-stef focus:ring-stef"
                                    />
                                    <div className="flex-1 min-w-0">
                                        <p className="text-sm font-semibold text-slate-900 truncate">{u.fullname || u.username}</p>
                                        <p className="text-[11px] text-slate-500 font-mono truncate">{u.username} · {u.role}</p>
                                    </div>
                                </label>
                            );
                        })}
                    </div>
                </div>

                <div className="flex justify-end">
                    <button data-testid="notif-send-btn" disabled={sending} type="submit" className="inline-flex items-center gap-2 rounded-md bg-stef px-5 h-11 text-sm font-heading font-bold text-white hover:bg-stef-hover transition-all disabled:opacity-60">
                        <Send className="h-4 w-4" />
                        {sending ? 'Envoi…' : `Envoyer (${selectedIds.length})`}
                    </button>
                </div>
            </form>

            {history.length > 0 && (
                <div className="mt-6">
                    <h3 className="font-heading text-sm font-bold uppercase tracking-wider text-slate-700 mb-3">Historique des envois</h3>
                    <div className="rounded-lg border border-slate-200 bg-white divide-y divide-slate-100" data-testid="notif-history">
                        {history.map((h) => (
                            <div key={h.id} className="p-4">
                                <div className="flex items-center gap-2 flex-wrap">
                                    <Bell className="h-3.5 w-3.5 text-stef" />
                                    <p className="font-heading font-bold text-sm text-slate-900">{h.title}</p>
                                    <span className="text-[11px] text-slate-400">·</span>
                                    <span className="text-[11px] text-slate-500">{new Date(h.at).toLocaleString('fr-FR')}</span>
                                </div>
                                <p className="mt-1 text-sm text-slate-700 whitespace-pre-wrap">{h.body}</p>
                                <p className="mt-1 text-[11px] text-slate-500">par {h.from} · {h.recipients_count} destinataire(s)</p>
                            </div>
                        ))}
                    </div>
                </div>
            )}
        </div>
    );
}

function LegacyLoginPanel() {
    const [enabled, setEnabled] = useState(null);
    const [saving, setSaving] = useState(false);

    useEffect(() => {
        api.get('/settings/admin')
            .then((r) => setEnabled(!!r.data?.legacy_login_enabled))
            .catch((e) => toast.error(e?.response?.data?.detail || 'Erreur de chargement'));
    }, []);

    const toggle = async (next) => {
        setSaving(true);
        try {
            const r = await api.patch('/settings/legacy-login', { enabled: next });
            setEnabled(!!r.data?.legacy_login_enabled);
            toast.success(next ? 'Ancien mot de passe activé' : 'Ancien mot de passe désactivé');
        } catch (err) {
            toast.error(err?.response?.data?.detail || 'Erreur');
        } finally {
            setSaving(false);
        }
    };

    if (enabled === null) return <p className="text-sm text-slate-400 italic">Chargement…</p>;

    return (
        <div>
            <div className="mb-4">
                <h2 className="font-heading text-xl sm:text-2xl font-black text-slate-900">Connexion ancien mot de passe</h2>
                <p className="text-sm text-slate-500">Réservé au super-admin. Permet aux utilisateurs qui ont encore leur mot de passe Gestion Palettes de se connecter à My Truck, puis de choisir leur code à 6 chiffres.</p>
            </div>

            <div className="rounded-lg border border-slate-200 bg-white p-5">
                <div className="flex items-start justify-between gap-4 flex-wrap">
                    <div className="flex items-start gap-3 min-w-0 flex-1">
                        <div className={`flex h-10 w-10 shrink-0 items-center justify-center rounded-md ${enabled ? 'bg-stef text-white' : 'bg-slate-100 text-slate-500'}`}>
                            <KeyRound className="h-5 w-5" />
                        </div>
                        <div className="min-w-0">
                            <p className="font-heading text-base font-bold text-slate-900">Mode "ancien mot de passe"</p>
                            <p className="mt-1 text-sm text-slate-600">
                                {enabled
                                    ? 'Activé : un bouton « Connexion ancien mot de passe » apparaît sur la page de login.'
                                    : 'Désactivé : seule la connexion par code à 6 chiffres est proposée.'}
                            </p>
                            <p className="mt-2 text-[11px] text-slate-500">À chaque connexion via ce mode, l\'utilisateur est ensuite obligé de définir un code à 6 chiffres.</p>
                        </div>
                    </div>
                    <button
                        data-testid="legacy-login-toggle"
                        onClick={() => toggle(!enabled)}
                        disabled={saving}
                        className={`inline-flex items-center gap-2 rounded-md px-5 h-11 text-sm font-heading font-bold transition-all disabled:opacity-60 ${
                            enabled
                                ? 'bg-red-600 text-white hover:bg-red-700'
                                : 'bg-stef text-white hover:bg-stef-hover'
                        }`}
                    >
                        {saving ? '…' : (enabled ? 'Désactiver' : 'Activer')}
                    </button>
                </div>
            </div>
        </div>
    );
}

// ===========================================================================
// ShiftsPanel — v18 : configuration auto-déco caristes par équipe (mathieu.u)
// ===========================================================================
const SHIFT_LABELS = {
    MATIN: 'Matin',
    APRES_MIDI: 'Après-midi',
    NUIT: 'Nuit',
};
const SHIFT_ORDER = ['MATIN', 'APRES_MIDI', 'NUIT'];

function ShiftsPanel() {
    const [loading, setLoading] = useState(true);
    const [saving, setSaving] = useState(false);
    const [enabled, setEnabled] = useState(false);
    const [shifts, setShifts] = useState({ MATIN: '14:00', APRES_MIDI: '22:00', NUIT: '06:00' });
    const [tz, setTz] = useState('Europe/Paris');

    const load = async () => {
        try {
            setLoading(true);
            const r = await api.get('/shift-config');
            setEnabled(!!r.data.enabled);
            setShifts({ ...shifts, ...(r.data.shifts || {}) });
            setTz(r.data.timezone || 'Europe/Paris');
        } catch (e) {
            toast.error('Impossible de charger la config équipes');
        } finally {
            setLoading(false);
        }
    };
    useEffect(() => { load(); }, []); // eslint-disable-line

    const save = async () => {
        try {
            setSaving(true);
            await api.put('/shift-config', { enabled, shifts });
            toast.success('Configuration enregistrée');
        } catch (e) {
            toast.error(e?.response?.data?.detail || 'Erreur enregistrement');
        } finally {
            setSaving(false);
        }
    };

    const testForce = async (code) => {
        if (!window.confirm(`Forcer la déconnexion immédiate des caristes de l'équipe ${SHIFT_LABELS[code]} ?`)) return;
        try {
            const r = await api.post('/shift-config/force-logout', { shift: code });
            toast.success(`${r.data.count} cariste(s) déconnecté(s) — équipe ${SHIFT_LABELS[code]}`);
            await loadConnected(selectedShift);
        } catch (e) {
            toast.error(e?.response?.data?.detail || 'Erreur');
        }
    };

    // ----- Liste des caristes connectés par équipe -----
    const [selectedShift, setSelectedShift] = useState('MATIN');
    const [connected, setConnected] = useState({ users: [], total_connected_app: 0 });
    const [loadingUsers, setLoadingUsers] = useState(false);

    const loadConnected = async (code) => {
        try {
            setLoadingUsers(true);
            const r = await api.get('/shift-config/connected-users', { params: { shift: code } });
            setConnected(r.data || { users: [], total_connected_app: 0 });
        } catch (e) {
            toast.error('Impossible de charger la liste');
        } finally {
            setLoadingUsers(false);
        }
    };

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

    // Auto-refresh toutes les 15 sec pour suivre les connexions/déconnexions
    useEffect(() => {
        const t = setInterval(() => loadConnected(selectedShift), 15000);
        return () => clearInterval(t);
    }, [selectedShift]); // eslint-disable-line

    const kickUser = async (u) => {
        if (!window.confirm(`Déconnecter ${u.fullname || u.username} maintenant ?`)) return;
        try {
            await api.post('/shift-config/force-logout-user', { user_id: u.id });
            toast.success(`${u.fullname || u.username} déconnecté`);
            await loadConnected(selectedShift);
        } catch (e) {
            toast.error(e?.response?.data?.detail || 'Erreur');
        }
    };

    if (loading) return <div className="text-sm text-slate-500">Chargement…</div>;

    return (
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-6 max-w-7xl">
            <div className="rounded-lg border border-slate-200 bg-white p-5 sm:p-6 shadow-sm">
                <div className="flex items-start gap-3 mb-4">
                    <Clock className="h-5 w-5 text-stef mt-1" />
                    <div className="flex-1">
                        <h2 className="font-heading text-lg font-bold text-slate-900">Déconnexion automatique des caristes</h2>
                        <p className="text-sm text-slate-600 mt-1">
                            À l&apos;heure de fin de service, les caristes de chaque équipe sont automatiquement déconnectés.
                            Fuseau horaire : <code className="text-xs">{tz}</code>
                        </p>
                    </div>
                </div>

                <div className="flex items-center justify-between rounded-md border border-slate-200 bg-slate-50 p-3 mb-5">
                    <div>
                        <div className="font-bold text-sm text-slate-900">État du système</div>
                        <div className="text-xs text-slate-600">
                            {enabled ? 'Activé — la déconnexion auto tourne en arrière-plan.' : 'Désactivé — aucun cariste n&apos;est déconnecté automatiquement.'}
                        </div>
                    </div>
                    <button
                        data-testid="shifts-toggle-btn"
                        onClick={() => setEnabled((v) => !v)}
                        className={`px-4 py-2 rounded-md text-sm font-bold transition ${
                            enabled ? 'bg-red-600 text-white hover:bg-red-700' : 'bg-stef text-white hover:bg-stef-hover'
                        }`}
                    >
                        {enabled ? 'Désactiver' : 'Activer'}
                    </button>
                </div>

                <div className="space-y-3">
                    {SHIFT_ORDER.map((code) => (
                        <div key={code} className="flex items-center gap-3 rounded-md border border-slate-200 bg-white p-3">
                            <div className="w-32 font-bold text-sm text-slate-900">{SHIFT_LABELS[code]}</div>
                            <label className="text-xs text-slate-600">Fin de service</label>
                            <input
                                type="time"
                                data-testid={`shift-end-${code}`}
                                value={shifts[code] || ''}
                                onChange={(e) => setShifts({ ...shifts, [code]: e.target.value })}
                                className="border border-slate-300 rounded-md px-3 py-1.5 text-sm font-mono"
                            />
                            <button
                                onClick={() => testForce(code)}
                                data-testid={`shift-force-${code}`}
                                className="ml-auto inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md border border-red-200 text-xs font-bold text-red-700 hover:bg-red-50"
                                title="Forcer la déconnexion immédiate des caristes de cette équipe"
                            >
                                <AlertTriangle className="h-3.5 w-3.5" />
                                Forcer
                            </button>
                        </div>
                    ))}
                </div>

                <div className="mt-5 flex items-center justify-between">
                    <p className="text-xs text-slate-500">
                        Seuls les utilisateurs ayant un rôle <strong>cariste</strong> ET une équipe assignée sont concernés.
                    </p>
                    <button
                        onClick={save}
                        disabled={saving}
                        data-testid="shifts-save-btn"
                        className="inline-flex items-center gap-2 px-5 py-2 rounded-md bg-stef text-white text-sm font-bold hover:bg-stef-hover disabled:opacity-60"
                    >
                        <Save className="h-4 w-4" />
                        {saving ? 'Enregistrement…' : 'Enregistrer'}
                    </button>
                </div>
            </div>

            {/* Caristes connectés par équipe */}
            <div className="rounded-lg border border-slate-200 bg-white p-5 sm:p-6 shadow-sm">
                <div className="flex items-start gap-3 mb-4">
                    <Users className="h-5 w-5 text-stef mt-1" />
                    <div className="flex-1">
                        <h2 className="font-heading text-lg font-bold text-slate-900">Caristes connectés par équipe</h2>
                        <p className="text-sm text-slate-600 mt-1">
                            Sélectionne une équipe pour voir les caristes assignés et qui est en ligne actuellement.
                            Auto-rafraîchi toutes les 15 sec — total app : <strong>{connected.total_connected_app}</strong> session(s) active(s).
                        </p>
                    </div>
                </div>

                <div className="flex flex-wrap gap-2 mb-4">
                    {SHIFT_ORDER.map((code) => (
                        <button
                            key={code}
                            data-testid={`shift-tab-${code}`}
                            onClick={() => setSelectedShift(code)}
                            className={`px-4 py-2 rounded-md text-sm font-bold border transition ${
                                selectedShift === code
                                    ? 'bg-stef text-white border-stef'
                                    : 'bg-white text-slate-700 border-slate-300 hover:bg-slate-50'
                            }`}
                        >
                            {SHIFT_LABELS[code]}
                        </button>
                    ))}
                    <button
                        onClick={() => loadConnected(selectedShift)}
                        className="ml-auto px-3 py-2 rounded-md text-xs font-bold border border-slate-300 text-slate-700 hover:bg-slate-50"
                        title="Rafraîchir"
                        data-testid="shift-refresh-btn"
                    >
                        Rafraîchir
                    </button>
                </div>

                {loadingUsers ? (
                    <div className="text-sm text-slate-500 py-6 text-center">Chargement…</div>
                ) : connected.users.length === 0 ? (
                    <div className="text-sm text-slate-500 py-6 text-center border border-dashed border-slate-300 rounded-md">
                        Aucun cariste assigné à l&apos;équipe {SHIFT_LABELS[selectedShift]}.
                    </div>
                ) : (
                    <div className="overflow-hidden rounded-md border border-slate-200">
                        <table className="w-full text-sm">
                            <thead className="bg-slate-50 text-xs uppercase tracking-wide text-slate-600">
                                <tr>
                                    <th className="text-left px-3 py-2">État</th>
                                    <th className="text-left px-3 py-2">Nom complet</th>
                                    <th className="text-left px-3 py-2">Identifiant</th>
                                    <th className="text-right px-3 py-2">Action</th>
                                </tr>
                            </thead>
                            <tbody>
                                {connected.users.map((u) => (
                                    <tr key={u.id} className="border-t border-slate-200" data-testid={`connected-row-${u.id}`}>
                                        <td className="px-3 py-2">
                                            {u.connected ? (
                                                <span className="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs font-bold bg-green-100 text-green-800">
                                                    <span className="h-2 w-2 rounded-full bg-green-500 animate-pulse"></span>
                                                    En ligne
                                                </span>
                                            ) : (
                                                <span className="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs font-bold bg-slate-100 text-slate-600">
                                                    <span className="h-2 w-2 rounded-full bg-slate-400"></span>
                                                    Hors ligne
                                                </span>
                                            )}
                                        </td>
                                        <td className="px-3 py-2 font-semibold text-slate-900">{u.fullname || '—'}</td>
                                        <td className="px-3 py-2 font-mono text-xs text-slate-600">{u.username}</td>
                                        <td className="px-3 py-2 text-right">
                                            {u.connected && (
                                                <button
                                                    onClick={() => kickUser(u)}
                                                    data-testid={`kick-user-${u.id}`}
                                                    className="inline-flex items-center gap-1.5 px-3 py-1 rounded-md border border-red-200 text-xs font-bold text-red-700 hover:bg-red-50"
                                                >
                                                    Déconnecter
                                                </button>
                                            )}
                                        </td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>
                )}
            </div>
        </div>
    );
}

export default function Settings() {
    const { user } = useAuth();
    const isSuperAdmin = (user?.username || '').toLowerCase() === 'mathieu.u';
    const canManageXdock = !!user?.can_manage_xdock_scripts || isSuperAdmin;
    const [tab, setTab] = useState('users');

    const tabs = [
        { id: 'users', label: 'Utilisateurs', icon: Users },
        { id: 'phrases', label: 'Phrases', icon: MessageSquareQuote },
        // { id: 'signature', label: 'Ma signature', icon: PenLine },  // v18 — feature signature email cachée (revoir plus tard)
    ];
    if (isSuperAdmin) {
        tabs.push({ id: 'shifts', label: 'Équipes & Auto-déco', icon: Clock });
    }
    if (canManageXdock) {
        tabs.push({ id: 'xdock', label: 'Scripts XDock+', icon: Power });
    }
    if (isSuperAdmin) {
        tabs.push({ id: 'legacy', label: 'Ancien MDP', icon: KeyRound });
        tabs.push({ id: 'updates', label: 'Mises à jour', icon: Package });
    }

    return (
        <Layout>
            <div className="mb-6 sm:mb-8">
                <p className="text-xs font-bold uppercase tracking-[0.2em] text-stef">Administration</p>
                <h1 className="mt-2 font-heading text-2xl sm:text-3xl lg:text-4xl font-black tracking-tight text-slate-900">Paramètres</h1>
                <p className="mt-1.5 text-sm sm:text-base text-slate-600">Utilisateurs et phrases prédéfinies.</p>
            </div>

            <div className="flex gap-2 mb-5 sm:mb-6 border-b border-slate-200 overflow-x-auto">
                {tabs.map((t) => (
                    <button
                        key={t.id}
                        data-testid={`tab-${t.id}`}
                        onClick={() => setTab(t.id)}
                        className={`inline-flex items-center gap-2 px-4 py-3 font-heading font-bold text-sm border-b-2 transition whitespace-nowrap ${
                            tab === t.id ? 'border-stef text-stef' : 'border-transparent text-slate-500 hover:text-slate-700'
                        }`}
                    >
                        <t.icon className="h-4 w-4" />
                        {t.label}
                    </button>
                ))}
            </div>

            {tab === 'users' && <UsersPanel />}
            {tab === 'phrases' && <PhrasesPanel />}
            {tab === 'signature' && <SignaturePanel />}
            {tab === 'shifts' && isSuperAdmin && <ShiftsPanel />}
            {tab === 'xdock' && canManageXdock && <XDockScriptsPanel />}
            {tab === 'legacy' && isSuperAdmin && <LegacyLoginPanel />}
            {tab === 'updates' && isSuperAdmin && <UpdatesPanel />}
        </Layout>
    );
}
