/**
 * mypro.ch · Admin — App React (JSX via Babel)
 * Administration globale : pilote toutes les centrales de la plateforme.
 *
 * Structure :
 *   <App>
 *     ├─ Login (magic-link, role=admin)
 *     └─ <Dashboard>
 *         └─ <Layout>
 *             ├─ <Sidebar> (navigation)
 *             └─ <Page*>   (page courante)
 */
const { useState, useEffect, useCallback, useMemo, useRef, useLayoutEffect } = React;
const { createPortal } = ReactDOM;

// ============================================================================
// DatePicker / TimePicker (cf. DOCS/APIS/ULTIME_DESIGN_ELEMENTS.md)
// Popover via portal, ouverture intelligente (top/bottom selon place dispo).
// ============================================================================
const _localizedMonthName = (lang, monthIndex) => {
    try {
        const d = new Date(2000, monthIndex, 1);
        const name = new Intl.DateTimeFormat(lang, { month: 'long' }).format(d);
        return name.charAt(0).toUpperCase() + name.slice(1);
    } catch (e) {
        return ['Jan','Fév','Mar','Avr','Mai','Juin','Juil','Août','Sep','Oct','Nov','Déc'][monthIndex];
    }
};
const _localizedDayShort = (lang, dayIndex) => {
    try {
        const d = new Date(2024, 0, 1 + dayIndex);
        const name = new Intl.DateTimeFormat(lang, { weekday: 'short' }).format(d).replace(/\.$/, '');
        return name.charAt(0).toUpperCase() + name.slice(1);
    } catch (e) {
        return ['Lun','Mar','Mer','Jeu','Ven','Sam','Dim'][dayIndex];
    }
};
const getDefaultTime = () => {
    const now = new Date();
    const m = now.getMinutes();
    let nextQ = Math.ceil((m + 1) / 15) * 15;
    let h = now.getHours();
    if (nextQ >= 60) { h++; nextQ = 0; }
    if (h >= 24) { h = 0; }
    return String(h).padStart(2, '0') + ':' + String(nextQ).padStart(2, '0');
};

function _usePopoverPosition(open, setOpen, { width = 360, estHeight = 360, position = 'auto' } = {}) {
    const btnRef = useRef(null);
    const popRef = useRef(null);
    const [coords, setCoords] = useState(null);
    const computePosition = useCallback(() => {
        const btn = btnRef.current;
        if (!btn) return;
        const r = btn.getBoundingClientRect();
        const spaceBelow = window.innerHeight - r.bottom;
        const spaceAbove = r.top;
        const wantTop = position === 'top'
            || (position === 'auto' && spaceBelow < estHeight && spaceAbove > spaceBelow);
        let left = r.left;
        const w = Math.min(width, window.innerWidth - 16);
        if (left + w > window.innerWidth - 8) left = Math.max(8, window.innerWidth - w - 8);
        setCoords({
            top: wantTop ? r.top - 8 : r.bottom + 8,
            left, btnWidth: r.width,
            placement: wantTop ? 'top' : 'bottom',
        });
    }, [width, estHeight, position]);
    useLayoutEffect(() => {
        if (!open) { setCoords(null); return; }
        computePosition();
        const onScroll = () => computePosition();
        window.addEventListener('scroll', onScroll, true);
        window.addEventListener('resize', onScroll);
        return () => {
            window.removeEventListener('scroll', onScroll, true);
            window.removeEventListener('resize', onScroll);
        };
    }, [open, computePosition]);
    useEffect(() => {
        if (!open) return;
        const onClick = (e) => {
            const t = e.target;
            if (btnRef.current?.contains(t)) return;
            if (popRef.current?.contains(t)) return;
            setOpen(false);
        };
        document.addEventListener('mousedown', onClick);
        return () => document.removeEventListener('mousedown', onClick);
    }, [open, setOpen]);
    return { btnRef, popRef, coords };
}

function _PickerButton({ open, icon, value, placeholder, onClick, btnRef }) {
    const accent = 'var(--color-primary, #B8956B)';
    return (
        <button ref={btnRef} type="button" onClick={onClick}
            style={{
                width: '100%', padding: '14px 14px', background: '#fff',
                border: '2px solid ' + (open ? accent : '#e5e7eb'),
                borderRadius: 12, textAlign: 'left',
                display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                gap: 8, cursor: 'pointer', fontSize: 14, fontWeight: 600,
                fontFamily: 'inherit', color: '#1e293b', transition: 'border-color 0.2s',
            }}>
            <span style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <i className={`fas ${icon}`} style={{ color: accent, fontSize: 14 }}></i>
                <span style={{ color: value ? '#1e293b' : '#94a3b8', fontWeight: 600 }}>
                    {value || placeholder}
                </span>
            </span>
            <i className={'fas fa-chevron-' + (open ? 'up' : 'down')} style={{ color: '#cbd5e1', fontSize: 10 }}></i>
        </button>
    );
}

function DatePicker({ value, onChange, minDate, placeholder = 'Choisir une date' }) {
    const [open, setOpen] = useState(false);
    const today = new Date(); today.setHours(0, 0, 0, 0);
    const initial = value ? new Date(value + 'T00:00:00') : today;
    const [viewYear, setViewYear] = useState(initial.getFullYear());
    const [viewMonth, setViewMonth] = useState(initial.getMonth());
    const { btnRef, popRef, coords } = _usePopoverPosition(open, setOpen, { width: 360, estHeight: 380 });
    const monthNames = useMemo(() => Array.from({ length: 12 }, (_, i) => _localizedMonthName('fr', i)), []);
    const dayNames = useMemo(() => Array.from({ length: 7 }, (_, i) => _localizedDayShort('fr', i)), []);

    const todayStr = today.getFullYear() + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0');
    const minStr = minDate === null ? null : (minDate || todayStr);

    const firstDay = new Date(viewYear, viewMonth, 1);
    let startDay = firstDay.getDay() - 1; if (startDay < 0) startDay = 6;
    const daysInMonth = new Date(viewYear, viewMonth + 1, 0).getDate();
    const cells = [];
    for (let i = 0; i < startDay; i++) cells.push(null);
    for (let d = 1; d <= daysInMonth; d++) cells.push(d);

    const accent = 'var(--color-primary, #B8956B)';
    const accentDark = 'var(--color-primary-dark, #A07D55)';

    const selectDay = (d) => {
        const v = viewYear + '-' + String(viewMonth + 1).padStart(2, '0') + '-' + String(d).padStart(2, '0');
        onChange(v); setOpen(false);
    };
    const prevMonth = () => { if (viewMonth === 0) { setViewMonth(11); setViewYear(viewYear - 1); } else setViewMonth(viewMonth - 1); };
    const nextMonth = () => { if (viewMonth === 11) { setViewMonth(0); setViewYear(viewYear + 1); } else setViewMonth(viewMonth + 1); };
    const prevYear = () => setViewYear(viewYear - 1);
    const nextYear = () => setViewYear(viewYear + 1);
    const formatDisplay = (v) => { if (!v) return null; const p = v.split('-'); return p[2] + '/' + p[1] + '/' + p[0]; };

    const navBtn = { width: 30, height: 30, borderRadius: '50%', border: 'none', background: '#f8fafc', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' };

    const popover = open && coords ? (
        <div ref={popRef}
            style={{
                position: 'fixed',
                top: coords.placement === 'top' ? undefined : coords.top,
                bottom: coords.placement === 'top' ? window.innerHeight - coords.top : undefined,
                left: coords.left,
                width: 360, maxWidth: 'calc(100vw - 16px)',
                background: '#fff', borderRadius: 16,
                border: '2px solid #f1f5f9', padding: 16, zIndex: 10000,
                boxShadow: coords.placement === 'top'
                    ? '0 -10px 40px rgba(0,0,0,0.18)'
                    : '0 10px 40px rgba(0,0,0,0.18)',
            }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16, gap: 4 }}>
                <div style={{ display: 'flex', gap: 4 }}>
                    <button type="button" onClick={prevYear} title="Année précédente" style={navBtn}><i className="fas fa-angle-double-left" style={{ color: '#64748b', fontSize: 11 }}></i></button>
                    <button type="button" onClick={prevMonth} title="Mois précédent" style={navBtn}><i className="fas fa-chevron-left" style={{ color: '#64748b', fontSize: 11 }}></i></button>
                </div>
                <span style={{ fontWeight: 700, fontSize: 15, color: '#1e293b' }}>{monthNames[viewMonth]} {viewYear}</span>
                <div style={{ display: 'flex', gap: 4 }}>
                    <button type="button" onClick={nextMonth} title="Mois suivant" style={navBtn}><i className="fas fa-chevron-right" style={{ color: '#64748b', fontSize: 11 }}></i></button>
                    <button type="button" onClick={nextYear} title="Année suivante" style={navBtn}><i className="fas fa-angle-double-right" style={{ color: '#64748b', fontSize: 11 }}></i></button>
                </div>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 4, marginBottom: 6 }}>
                {dayNames.map((dn, i) => (
                    <div key={i} style={{ height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, fontWeight: 700, color: '#94a3b8', textTransform: 'uppercase', letterSpacing: 0.5 }}>{dn}</div>
                ))}
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 4 }}>
                {cells.map((d, i) => {
                    if (!d) return <div key={'e' + i} style={{ height: 40 }}></div>;
                    const dateStr = viewYear + '-' + String(viewMonth + 1).padStart(2, '0') + '-' + String(d).padStart(2, '0');
                    const isSelected = dateStr === value;
                    const isToday = dateStr === todayStr;
                    const isPast = minStr ? dateStr < minStr : false;
                    return (
                        <button key={d} type="button" disabled={isPast}
                            onClick={() => { if (!isPast) selectDay(d); }}
                            style={{
                                width: 40, height: 40, borderRadius: 12,
                                border: isToday && !isSelected ? '2px solid ' + accent : '2px solid transparent',
                                background: isSelected ? `linear-gradient(135deg, ${accent}, ${accentDark})` : (isToday ? 'rgba(184,149,107,0.08)' : 'transparent'),
                                color: isSelected ? '#fff' : (isPast ? '#cbd5e1' : '#1e293b'),
                                fontSize: 14, fontWeight: isSelected || isToday ? 700 : 500,
                                cursor: isPast ? 'not-allowed' : 'pointer',
                                display: 'flex', alignItems: 'center', justifyContent: 'center',
                                margin: '0 auto', transition: 'all 0.15s',
                            }}>
                            {d}
                        </button>
                    );
                })}
            </div>
        </div>
    ) : null;

    return (
        <div style={{ position: 'relative' }}>
            <_PickerButton open={open} icon="fa-calendar-alt" value={formatDisplay(value)} placeholder={placeholder} onClick={() => setOpen(!open)} btnRef={btnRef} />
            {popover && createPortal(popover, document.body)}
        </div>
    );
}

function TimePicker({ value, onChange, placeholder = 'Choisir une heure', autoDefault = false }) {
    const [open, setOpen] = useState(false);
    const { btnRef, popRef, coords } = _usePopoverPosition(open, setOpen, { width: 200, estHeight: 240 });
    const listRef = useRef(null);
    useEffect(() => { if (autoDefault && !value) onChange(getDefaultTime()); }, []);
    useEffect(() => {
        if (open && listRef.current && value) {
            const container = listRef.current;
            const slots = container.children;
            for (let i = 0; i < slots.length; i++) {
                if (slots[i].dataset.slot === value) {
                    const target = slots[i];
                    container.scrollTop = target.offsetTop - (container.clientHeight / 2) + (target.clientHeight / 2);
                    break;
                }
            }
        }
    }, [open, coords]);
    const slots = useMemo(() => {
        const s = [];
        for (let hh = 0; hh < 24; hh++) for (let mm = 0; mm < 60; mm += 15) s.push(String(hh).padStart(2, '0') + ':' + String(mm).padStart(2, '0'));
        return s;
    }, []);
    const accent = 'var(--color-primary, #B8956B)';
    const accentDark = 'var(--color-primary-dark, #A07D55)';
    const popover = open && coords ? (
        <div ref={(el) => { popRef.current = el; listRef.current = el; }}
            style={{
                position: 'fixed',
                top: coords.placement === 'top' ? undefined : coords.top,
                bottom: coords.placement === 'top' ? window.innerHeight - coords.top : undefined,
                left: coords.left,
                width: Math.max(coords.btnWidth || 200, 180),
                maxWidth: 'calc(100vw - 16px)',
                background: '#fff', borderRadius: 16,
                border: '2px solid #f1f5f9', zIndex: 10000,
                boxShadow: coords.placement === 'top'
                    ? '0 -10px 40px rgba(0,0,0,0.18)'
                    : '0 10px 40px rgba(0,0,0,0.18)',
                maxHeight: 240, overflowY: 'auto',
            }}>
            {slots.map((slot) => {
                const isSelected = slot === value;
                return (
                    <button key={slot} data-slot={slot} type="button"
                        onClick={() => { onChange(slot); setOpen(false); }}
                        style={{
                            display: 'block', width: '100%', padding: '10px 16px',
                            fontSize: 14, fontWeight: isSelected ? 700 : 400,
                            fontFamily: 'monospace', border: 'none',
                            borderBottom: '1px solid #f1f5f9',
                            background: isSelected ? `linear-gradient(135deg, ${accent}, ${accentDark})` : 'transparent',
                            color: isSelected ? '#fff' : '#1e293b',
                            cursor: 'pointer', textAlign: 'left',
                        }}>
                        {slot}
                    </button>
                );
            })}
        </div>
    ) : null;
    return (
        <div style={{ position: 'relative' }}>
            <_PickerButton open={open} icon="fa-clock" value={value} placeholder={placeholder} onClick={() => setOpen(!open)} btnRef={btnRef} />
            {popover && createPortal(popover, document.body)}
        </div>
    );
}

// DateTimePicker : combo date + heure côte à côte (stocke "YYYY-MM-DDTHH:MM")
function DateTimePicker({ value, onChange, minDate }) {
    const [datePart, timePart] = (() => {
        if (!value) return ['', ''];
        const v = String(value).replace(' ', 'T');
        const [d, t] = v.split('T');
        return [d || '', (t || '').slice(0, 5)];
    })();
    const update = (d, t) => {
        if (!d && !t) { onChange(''); return; }
        onChange(`${d || ''}${d && t ? 'T' : ''}${t || ''}`);
    };
    return (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 160px', gap: 8 }}>
            <DatePicker value={datePart} onChange={(v) => update(v, timePart)} minDate={minDate} />
            <TimePicker value={timePart} onChange={(v) => update(datePart, v)} />
        </div>
    );
}

// ============================================================================
// Toast
// ============================================================================
let _toastSetter = null;
function toast(msg, type = 'success') { if (_toastSetter) _toastSetter({ msg, type, id: Date.now() }); }
function ToastContainer() {
    const [t, set] = useState(null);
    useEffect(() => { _toastSetter = set; return () => { _toastSetter = null; }; }, []);
    useEffect(() => { if (t) { const id = setTimeout(() => set(null), 3000); return () => clearTimeout(id); } }, [t]);
    if (!t) return null;
    return <div className={`toast toast-${t.type}`}>{t.msg}</div>;
}

// ============================================================================
// Modal & Confirm
// ============================================================================
function Modal({ title, onClose, children, footer, size = 'md' }) {
    return (
        <div className="modal-backdrop" onClick={onClose}>
            <div className="modal" style={{ maxWidth: size === 'xl' ? 1120 : size === 'lg' ? 920 : 720 }} onClick={e => e.stopPropagation()}>
                <div className="modal-header">
                    <h3 className="font-bold text-lg">{title}</h3>
                    <button onClick={onClose} className="text-gray-400 hover:text-gray-700"><i className="fas fa-times"></i></button>
                </div>
                <div className="modal-body">{children}</div>
                {footer && <div className="modal-footer">{footer}</div>}
            </div>
        </div>
    );
}
function ConfirmDialog({ title, message, confirmLabel = 'Confirmer', danger, onConfirm, onCancel }) {
    return (
        <Modal title={title} onClose={onCancel} footer={<>
            <button className="btn btn-secondary" onClick={onCancel}>Annuler</button>
            <button className={`btn ${danger ? 'btn-danger' : 'btn-primary'}`} onClick={onConfirm}>{confirmLabel}</button>
        </>}>
            <p className="text-sm text-gray-700">{message}</p>
        </Modal>
    );
}

// ============================================================================
// Form atoms
// ============================================================================
function Field({ label, children, span1, hint }) {
    return (
        <div className={`field ${span1 ? 'md:col-span-1' : ''}`}>
            <label>{label}</label>
            {children}
            {hint && <p className="text-xs text-gray-400 mt-1">{hint}</p>}
        </div>
    );
}
function TextInput({ value, onChange, type = 'text', placeholder, required, disabled }) {
    return <input type={type} className="input" value={value ?? ''} required={required} disabled={disabled}
        placeholder={placeholder} onChange={e => onChange(e.target.value)} />;
}
function TextArea({ value, onChange, rows = 3 }) {
    return <textarea className="input" rows={rows} value={value ?? ''} onChange={e => onChange(e.target.value)} />;
}
function Select({ value, onChange, options, placeholder = '— choisir —' }) {
    return (
        <select className="input" value={value ?? ''} onChange={e => onChange(e.target.value)}>
            <option value="">{placeholder}</option>
            {options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
        </select>
    );
}
function Checkbox({ value, onChange, label }) {
    return (
        <label className="inline-flex items-center gap-2 text-sm cursor-pointer">
            <input type="checkbox" checked={!!value} onChange={e => onChange(e.target.checked ? 1 : 0)} className="w-4 h-4" />
            {label}
        </label>
    );
}
function Toggle({ value, onChange }) {
    return (
        <button onClick={() => onChange(value ? 0 : 1)}
                className={`relative w-10 h-6 rounded-full transition ${value ? 'bg-violet-600' : 'bg-gray-300'}`}>
            <span className={`absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full transition transform ${value ? 'translate-x-4' : ''}`}></span>
        </button>
    );
}

// ============================================================================
// TabsView
// ============================================================================
function TabsView({ tabs, initial }) {
    const [active, setActive] = useState(initial || tabs[0].id);
    const current = tabs.find(t => t.id === active) || tabs[0];
    return (
        <div>
            <div className="tabs-bar">
                {tabs.map(t => (
                    <button key={t.id} className={`tab-link ${active === t.id ? 'active' : ''}`}
                        onClick={() => setActive(t.id)}>
                        {t.icon && <i className={`fas fa-${t.icon}`}></i>}{t.label}
                    </button>
                ))}
            </div>
            <div>{typeof current.render === 'function' ? current.render() : current.render}</div>
        </div>
    );
}

// ============================================================================
// StatCard
// ============================================================================
function StatCard({ label, value, icon, color = '#7c3aed' }) {
    return (
        <div className="card">
            <div className="flex items-center gap-3 mb-2">
                <div className="w-10 h-10 rounded-lg flex items-center justify-center"
                     style={{ background: color + '15', color }}>
                    <i className={`fas fa-${icon}`}></i>
                </div>
                <div className="text-xs text-gray-500">{label}</div>
            </div>
            <div className="text-2xl font-bold">{value ?? 0}</div>
        </div>
    );
}

// ============================================================================
// useResource — petit hook generic
// ============================================================================
function useResource(fn, deps = []) {
    const [data, setData] = useState(null);
    const [err, setErr]   = useState('');
    const reload = useCallback(() => {
        setData(null); setErr('');
        fn().then(setData).catch(e => setErr(e.message));
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, deps);
    useEffect(() => { reload(); }, [reload]);
    return { data, err, reload, setData };
}

// ============================================================================
// LOGIN
// ============================================================================
function Login() {
    const [email, setEmail] = useState('');
    const [sending, setSending] = useState(false);
    const [sent, setSent] = useState(false);
    const [err, setErr] = useState('');

    async function submit(e) {
        e.preventDefault();
        setErr(''); setSending(true);
        try {
            await MyProAuth.requestMagic(email.trim().toLowerCase());
            setSent(true);
        } catch (e) { setErr(e.message); }
        finally { setSending(false); }
    }

    return (
        <div className="min-h-screen flex items-center justify-center px-4">
            <div className="card w-full max-w-md">
                <div className="text-center mb-6">
                    <div className="inline-flex items-center justify-center w-14 h-14 rounded-2xl mb-4"
                         style={{ background: 'linear-gradient(135deg, #7c3aed, #6366f1)' }}>
                        <i className="fas fa-shield-halved text-white text-2xl"></i>
                    </div>
                    <h1 className="text-2xl font-bold mb-1">mypro.ch · Admin</h1>
                    <p className="text-gray-500 text-sm">Administration globale de la plateforme</p>
                </div>
                {sent ? (
                    <div className="text-center py-4">
                        <i className="fas fa-envelope-open-text text-4xl text-violet-500 mb-3"></i>
                        <h3 className="font-semibold mb-1">Vérifiez vos emails</h3>
                        <p className="text-sm text-gray-500 mb-4">Un lien a été envoyé à <strong>{email}</strong></p>
                        <button className="btn btn-secondary" onClick={() => { setSent(false); setEmail(''); }}>
                            Utiliser une autre adresse
                        </button>
                    </div>
                ) : (
                    <form onSubmit={submit}>
                        <Field label="Adresse email admin">
                            <input type="email" required autoFocus className="input"
                                placeholder="admin@mypro.ch" value={email}
                                onChange={e => setEmail(e.target.value)} />
                        </Field>
                        {err && <div className="text-sm text-red-600 mb-3">{err}</div>}
                        <button type="submit" className="btn btn-primary w-full" disabled={sending}>
                            {sending ? <span className="spinner-dot"></span> : 'Recevoir un lien de connexion'}
                        </button>
                        <p className="text-xs text-gray-400 text-center mt-4">
                            Accès réservé aux administrateurs autorisés.
                        </p>
                    </form>
                )}
            </div>
        </div>
    );
}

// ============================================================================
// LAYOUT — sidebar + main
// ============================================================================
const NAV = [
    { type: 'item',  id: 'dashboard',    label: 'Tableau de bord',  icon: 'gauge' },
    { type: 'item',  id: 'diffusion',    label: 'Diffusion',        icon: 'tower-broadcast' },
    { type: 'group', label: 'Clients' },
    { type: 'item',  id: 'accounts',     label: 'Comptes clients',  icon: 'user-tie' },
    { type: 'item',  id: 'operators',    label: 'Centrales',        icon: 'building' },
    { type: 'group', label: 'Activité' },
    { type: 'item',  id: 'bookings',     label: 'Réservations',     icon: 'route' },
    { type: 'item',  id: 'drivers',      label: 'Chauffeurs',       icon: 'taxi' },
    { type: 'group', label: 'Apporteurs d\'affaires' },
    { type: 'item',  id: 'partners',     label: 'Partenaires',      icon: 'handshake' },
    { type: 'item',  id: 'commissions',  label: 'Commissions',      icon: 'money-bill-trend-up' },
    { type: 'group', label: 'Infrastructure' },
    { type: 'item',  id: 'sms',          label: 'SMS',              icon: 'sms' },
    { type: 'item',  id: 'sites',        label: 'Sites internets',  icon: 'globe' },
    { type: 'group', label: 'Plateforme' },
    { type: 'item',  id: 'admins',       label: 'Administrateurs',  icon: 'user-shield' },
];

function Layout({ user, page, setPage, children }) {
    return (
        <div className="min-h-screen flex">
            <aside className="hidden md:flex sidebar h-screen sticky top-0">
                <div className="sidebar-header">
                    <div className="sidebar-logo">
                        <div className="sidebar-logo-icon"><i className="fas fa-shield-halved"></i></div>
                        <div>
                            <div className="font-bold text-sm">mypro.ch</div>
                            <div className="text-xs text-gray-500 truncate" style={{ maxWidth: 160 }}>{user.name || user.email}</div>
                        </div>
                    </div>
                </div>
                <nav className="sidebar-nav">
                    {NAV.map((n, i) => n.type === 'group'
                        ? <div key={i} className="sidebar-section-title">{n.label}</div>
                        : <div key={n.id} className={`sidebar-item ${page === n.id ? 'active' : ''}`}
                               onClick={() => setPage(n.id)}>
                              <i className={`sidebar-item-icon fas fa-${n.icon}`}></i>{n.label}
                          </div>
                    )}
                </nav>
                <div className="sidebar-footer">
                    <button onClick={() => MyProAuth.logout()}
                            className="sidebar-item w-full"
                            style={{ color: 'var(--danger)' }}>
                        <i className="sidebar-item-icon fas fa-sign-out-alt"></i> Déconnexion
                    </button>
                </div>
            </aside>
            <main className="flex-1 overflow-auto">
                <div className="md:hidden bg-white border-b border-gray-200 p-4 flex items-center justify-between">
                    <div className="flex items-center gap-2">
                        <div className="sidebar-logo-icon" style={{ width: '2rem', height: '2rem' }}><i className="fas fa-shield-halved"></i></div>
                        <span className="font-bold">mypro.ch · Admin</span>
                    </div>
                    <select value={page} onChange={e => setPage(e.target.value)} className="input" style={{ maxWidth: 220 }}>
                        {NAV.filter(n => n.type === 'item').map(n =>
                            <option key={n.id} value={n.id}>{n.label}</option>)}
                    </select>
                </div>
                <div className="p-6 max-w-7xl mx-auto">{children}</div>
            </main>
            <ToastContainer />
        </div>
    );
}

// ============================================================================
// DASHBOARD
// ============================================================================
function PageDashboard({ user }) {
    const { data, err } = useResource(() => MyProAPI.overview(), []);
    if (err)   return <div className="card text-red-600">{err}</div>;
    if (!data) return <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>;

    return (
        <div>
            <div className="mb-6">
                <h1 className="text-2xl font-bold">Bienvenue {user.name || user.email}</h1>
                <p className="text-gray-500 text-sm">Vue d'ensemble de la plateforme mypro.ch</p>
            </div>
            <div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
                <StatCard label="Comptes clients"    value={data.accounts}        icon="user-tie"     color="#7c3aed" />
                <StatCard label="Centrales"          value={data.centrals}        icon="building"     color="#6366f1" />
                <StatCard label="Sites actifs"       value={data.websites_active} icon="globe"        color="#0ea5e9" />
                <StatCard label="Chauffeurs actifs"  value={data.drivers_active}  icon="taxi"         color="#10b981" />
                <StatCard label="Courses aujourd'hui" value={data.bookings_today} icon="route"        color="#4f46e5" />
                <StatCard label="Courses 30j"        value={data.bookings_30d}    icon="chart-line"   color="#0ea5e9" />
                <StatCard label="SMS restants (tous)" value={data.sms_balance_total} icon="sms"      color={data.sms_alerts > 0 ? '#ef4444' : '#10b981'} />
                <StatCard label="Alertes SMS bas"    value={data.sms_alerts}      icon="exclamation-triangle" color="#f59e0b" />
            </div>
            <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
                <StatCard label="Partenaires actifs" value={data.partners}     icon="handshake" color="#ec4899" />
                <StatCard label="SMS envoyés 30j"    value={data.sms_sent_30d} icon="paper-plane" color="#6366f1" />
                <StatCard label="Administrateurs"    value={data.admins}       icon="user-shield" color="#1f2937" />
            </div>
        </div>
    );
}

// ============================================================================
// ACCOUNTS (clients propriétaires de centrales)
// ============================================================================
function PageAccounts() {
    const [search, setSearch] = useState('');
    const { data, err, reload } = useResource(() => MyProAPI.accounts(search ? { q: search } : {}), [search]);
    const [editing, setEditing] = useState(null);
    const [detail, setDetail] = useState(null);
    const [confirm, setConfirm] = useState(null);

    async function save() {
        try {
            if (editing.id) await MyProAPI.updateAccount(editing.id, stripMeta(editing));
            else await MyProAPI.createAccount(editing);
            toast('Enregistré'); setEditing(null); reload();
        } catch (e) { toast(e.message, 'error'); }
    }
    async function doDelete(id) {
        try { await MyProAPI.deleteAccount(id); toast('Supprimé'); setConfirm(null); reload(); }
        catch (e) { toast(e.message, 'error'); }
    }

    return (
        <div>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Comptes clients</h1>
                    <div className="page-subtitle">Propriétaires de centrales (un compte peut posséder plusieurs centrales).</div>
                </div>
                <button className="btn btn-primary" onClick={() => setEditing({ is_active: 1, is_validated: 0, tva_rate: 7.7 })}>
                    <i className="fas fa-plus"></i> Nouveau client
                </button>
            </div>
            <div className="toolbar">
                <input className="search-input" placeholder="Rechercher (email, nom, société)…"
                       value={search} onChange={e => setSearch(e.target.value)} />
            </div>
            {err && <div className="card text-red-600 mb-3">{err}</div>}
            {!data ? <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
             : (data.accounts || []).length === 0 ? <div className="card text-center text-gray-500 py-10">Aucun compte</div>
             : (
                <div className="card" style={{ padding: 0, overflow: 'auto' }}>
                    <table className="data">
                        <thead><tr>
                            <th>Email</th><th>Nom / Société</th><th>Téléphone</th>
                            <th>Centrales</th><th>Sites</th><th>Statut</th><th></th>
                        </tr></thead>
                        <tbody>
                            {data.accounts.map(a => (
                                <tr key={a.id} className="row-link" onClick={() => setDetail(a.id)}>
                                    <td className="font-mono text-xs">{a.email}</td>
                                    <td>
                                        <div className="font-semibold">{a.name || '—'}</div>
                                        <div className="text-xs text-gray-500">{a.company || '—'}</div>
                                    </td>
                                    <td className="text-sm">{a.phone || '—'}</td>
                                    <td><span className="badge badge-violet">{a.centrals_count || 0}</span></td>
                                    <td><span className="badge badge-info">{a.websites_count || 0}</span></td>
                                    <td>
                                        {a.is_active
                                            ? (a.is_validated ? <span className="badge badge-success">Validé</span>
                                                              : <span className="badge badge-warn">En attente</span>)
                                            : <span className="badge badge-muted">Inactif</span>}
                                    </td>
                                    <td onClick={e => e.stopPropagation()} className="whitespace-nowrap">
                                        <button className="text-gray-500 hover:text-violet-600 px-2"
                                                onClick={() => setEditing(a)}><i className="fas fa-pen"></i></button>
                                        <button className="text-gray-500 hover:text-red-600 px-2"
                                                onClick={() => setConfirm(a)}><i className="fas fa-trash"></i></button>
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            )}
            {editing && <AccountEditModal account={editing} setAccount={setEditing} onClose={() => setEditing(null)} onSave={save} />}
            {detail && <AccountDetailModal id={detail} onClose={() => setDetail(null)} />}
            {confirm && (
                <ConfirmDialog title="Supprimer le compte" danger
                    message={`Le compte ${confirm.email} sera supprimé (les centrales/sites associés seront détachés mais conservés).`}
                    confirmLabel="Supprimer"
                    onCancel={() => setConfirm(null)}
                    onConfirm={() => doDelete(confirm.id)} />
            )}
        </div>
    );
}

function AccountEditModal({ account, setAccount, onClose, onSave }) {
    const set = (k, v) => setAccount(a => ({ ...a, [k]: v }));
    return (
        <Modal title={account.id ? 'Modifier le client' : 'Nouveau client'} onClose={onClose} size="lg"
            footer={<>
                <button className="btn btn-secondary" onClick={onClose}>Annuler</button>
                <button className="btn btn-primary" onClick={onSave}>Enregistrer</button>
            </>}>
            <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
                <Field label="Email"><TextInput type="email" value={account.email} onChange={v => set('email', v)} required /></Field>
                <Field label="Nom du contact"><TextInput value={account.name} onChange={v => set('name', v)} /></Field>
                <Field label="Raison sociale"><TextInput value={account.company} onChange={v => set('company', v)} /></Field>
                <Field label="Nom commercial"><TextInput value={account.company_name} onChange={v => set('company_name', v)} /></Field>
                <Field label="N° société / SIRET"><TextInput value={account.company_number} onChange={v => set('company_number', v)} /></Field>
                <Field label="Téléphone"><TextInput value={account.phone} onChange={v => set('phone', v)} /></Field>
                <div className="md:col-span-2"><Field label="Adresse"><TextArea value={account.address} onChange={v => set('address', v)} rows={2} /></Field></div>
                <Field label="N° TVA"><TextInput value={account.tva_number} onChange={v => set('tva_number', v)} /></Field>
                <Field label="Taux TVA (%)"><TextInput type="number" value={account.tva_rate} onChange={v => set('tva_rate', parseFloat(v))} /></Field>
                <Field label="Banque"><TextInput value={account.bank_name} onChange={v => set('bank_name', v)} /></Field>
                <Field label="IBAN"><TextInput value={account.bank_iban} onChange={v => set('bank_iban', v)} /></Field>
                <Field label="SWIFT/BIC"><TextInput value={account.bank_swift} onChange={v => set('bank_swift', v)} /></Field>
                <Field label="Actif"><Checkbox value={account.is_active} onChange={v => set('is_active', v)} label="Compte actif" /></Field>
                <Field label="Validé"><Checkbox value={account.is_validated} onChange={v => set('is_validated', v)} label="Compte validé par admin" /></Field>
                <div className="md:col-span-2"><Field label="Notes"><TextArea value={account.notes} onChange={v => set('notes', v)} rows={3} /></Field></div>
            </div>
        </Modal>
    );
}

function AccountDetailModal({ id, onClose }) {
    const { data, err } = useResource(() => MyProAPI.account(id), [id]);
    if (err) return <Modal title="Erreur" onClose={onClose}><div className="text-red-600">{err}</div></Modal>;
    if (!data) return <Modal title="Compte" onClose={onClose}><div className="flex justify-center py-10"><div className="loading-spinner"></div></div></Modal>;
    const a = data.account;
    return (
        <Modal title={a.name || a.email} onClose={onClose} size="lg">
            <TabsView tabs={[
                { id: 'info', label: 'Informations', icon: 'info-circle', render: () => (
                    <div>
                        {[
                            ['Email', a.email], ['Nom', a.name], ['Société', a.company], ['Nom commercial', a.company_name],
                            ['N° société', a.company_number], ['Téléphone', a.phone], ['Adresse', a.address],
                            ['N° TVA', a.tva_number], ['Taux TVA', a.tva_rate ? a.tva_rate + ' %' : null],
                            ['Banque', a.bank_name], ['IBAN', a.bank_iban], ['SWIFT', a.bank_swift],
                            ['Statut', a.is_active ? (a.is_validated ? 'Validé' : 'En attente') : 'Inactif'],
                            ['Créé le', a.created], ['Modifié le', a.modified],
                            ['Notes', a.notes],
                        ].filter(([, v]) => v).map(([k, v]) => (
                            <div key={k} className="detail-row"><div className="label">{k}</div><div>{v}</div></div>
                        ))}
                    </div>
                )},
                { id: 'centrals', label: `Centrales (${(data.centrals || []).length})`, icon: 'building', render: () => (
                    (data.centrals || []).length === 0
                        ? <div className="text-sm text-gray-500 py-6 text-center">Aucune centrale</div>
                        : <table className="data"><thead><tr><th>ID</th><th>Label</th><th>Clé</th><th>Adresse</th><th>Statut</th></tr></thead>
                            <tbody>{data.centrals.map(c => (
                                <tr key={c.id}><td>{c.id}</td><td>{c.label}</td><td className="font-mono text-xs">{c.key}</td>
                                <td>{c.address}</td><td>{c.is_standby ? <span className="badge badge-warn">Standby</span> : <span className="badge badge-success">Actif</span>}</td></tr>
                            ))}</tbody></table>
                )},
                { id: 'websites', label: `Sites (${(data.websites || []).length})`, icon: 'globe', render: () => (
                    (data.websites || []).length === 0
                        ? <div className="text-sm text-gray-500 py-6 text-center">Aucun site</div>
                        : <table className="data"><thead><tr><th>ID</th><th>Société</th><th>Partnerkey</th><th>SMS</th><th>Statut</th></tr></thead>
                            <tbody>{data.websites.map(w => (
                                <tr key={w.id}><td>{w.id}</td><td>{w.company}</td><td className="font-mono text-xs">{w.partnerkey}</td>
                                <td>{w.sms_balance}</td>
                                <td>{w.is_closed ? <span className="badge badge-danger">Fermé</span>
                                    : w.is_active ? <span className="badge badge-success">Actif</span>
                                    : <span className="badge badge-muted">Inactif</span>}</td></tr>
                            ))}</tbody></table>
                )},
            ]} />
        </Modal>
    );
}

// ============================================================================
// OPERATORS (centrales + websites) — module riche avec tabs
// ============================================================================
function PageOperators() {
    const [search, setSearch] = useState('');
    const { data, err, reload } = useResource(() => MyProAPI.operators(search ? { q: search } : {}), [search]);
    const [editing, setEditing] = useState(null);
    const [selectedId, setSelectedId] = useState(null);
    const [confirm, setConfirm] = useState(null);

    async function doDelete(id) {
        try { await MyProAPI.deleteOperator(id); toast('Centrale supprimée'); setConfirm(null); reload(); }
        catch (e) { toast(e.message, 'error'); }
    }
    async function createOperator(data) {
        try { await MyProAPI.createOperator(data); toast('Centrale créée'); setEditing(null); reload(); }
        catch (e) { toast(e.message, 'error'); }
    }

    // Vue détail plein écran
    if (selectedId) {
        return <OperatorDetailPage
            id={selectedId}
            onBack={() => { setSelectedId(null); reload(); }}
            onDeleted={() => { setSelectedId(null); reload(); }}
        />;
    }

    return (
        <div>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Centrales VTC</h1>
                    <div className="page-subtitle">Chaque centrale est rattachée à un compte client et possède un site (couple <code>central</code> + <code>website</code>).</div>
                </div>
                <button className="btn btn-primary" onClick={() => setEditing({})}>
                    <i className="fas fa-plus"></i> Nouvelle centrale
                </button>
            </div>
            <div className="toolbar">
                <input className="search-input" placeholder="Rechercher (société, clé, email)…"
                       value={search} onChange={e => setSearch(e.target.value)} />
                <div className="text-xs text-gray-500 ml-auto">
                    {data?.operators ? `${data.operators.length} centrale${data.operators.length > 1 ? 's' : ''}` : ''}
                </div>
            </div>
            {err && <div className="card text-red-600 mb-3">{err}</div>}
            {!data ? <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
             : (data.operators || []).length === 0 ? <div className="card text-center text-gray-500 py-10">Aucune centrale</div>
             : (
                <div className="space-y-2">
                    {data.operators.map(o => (
                        <OperatorRow key={o.id} o={o}
                            onOpen={() => setSelectedId(o.id)}
                            onDelete={() => setConfirm(o)} />
                    ))}
                </div>
            )}
            {editing && <OperatorCreateModal onClose={() => setEditing(null)} onSave={createOperator} />}
            {confirm && (
                <ConfirmDialog title="Supprimer la centrale" danger
                    message={`La centrale "${confirm.company}" et son site (${confirm.partnerkey}) seront supprimés. Cette action est irréversible.`}
                    confirmLabel="Supprimer définitivement"
                    onCancel={() => setConfirm(null)}
                    onConfirm={() => doDelete(confirm.id)} />
            )}
        </div>
    );
}

/* ─── Une ligne (carte) opérateur ─── */
function OperatorRow({ o, onOpen, onDelete }) {
    const status = o.is_closed
        ? { cls: 'badge-danger',  label: 'Fermé' }
        : o.central_standby
        ? { cls: 'badge-warn',    label: 'Standby' }
        : o.is_active
        ? { cls: 'badge-success', label: 'Actif' }
        : { cls: 'badge-muted',   label: 'Inactif' };

    const initial = (o.company || o.central_label || '?').trim().charAt(0).toUpperCase();
    const color = o.color || '#7c3aed';

    return (
        <div className="card row-link operator-row" onClick={onOpen}
             style={{ padding: '14px 18px', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 16 }}>

            {/* Avatar / couleur */}
            <div className="flex items-center justify-center text-white font-bold flex-shrink-0"
                 style={{ width: 44, height: 44, borderRadius: 10, background: color, fontSize: 18 }}>
                {initial}
            </div>

            {/* Identité */}
            <div className="min-w-0 flex-shrink-0" style={{ width: 220 }}>
                <div className="font-semibold truncate">{o.company || o.central_label || '—'}</div>
                <div className="text-xs text-gray-500 font-mono truncate">app.mypro.ch/{o.partnerkey}/</div>
            </div>

            {/* Compte */}
            <div className="hidden md:block min-w-0 flex-shrink-0" style={{ width: 200 }}>
                <div className="text-sm truncate">{o.account_name || '—'}</div>
                <div className="text-xs text-gray-500 truncate">{o.account_email}</div>
            </div>

            {/* Stats inline */}
            <div className="hidden lg:flex items-center gap-4 flex-1 min-w-0">
                <Stat icon="user-tie"  label="Chauffeurs" value={o.drivers_count}  alert={o.drivers_count == 0} />
                <Stat icon="car"       label="Véhicules"  value={o.vehicles_count} alert={o.vehicles_count == 0} />
                <Stat icon="route"     label="Courses"    value={o.bookings_count} />
                <Stat icon="comment-sms" label="SMS"      value={o.sms_balance ?? '—'} alert={o.sms_balance != null && o.sms_balance <= 20} />
            </div>

            {/* Statut + actions */}
            <div className="flex items-center gap-2 flex-shrink-0 ml-auto" onClick={e => e.stopPropagation()}>
                <span className={`badge ${status.cls}`}>{status.label}</span>
                <a className="text-gray-400 hover:text-violet-600 px-2 py-1" target="_blank" rel="noopener"
                   href={`https://app.mypro.ch/${o.partnerkey}/`} title="Ouvrir le site">
                    <i className="fas fa-external-link-alt"></i>
                </a>
                <button className="text-gray-400 hover:text-red-600 px-2 py-1"
                        onClick={onDelete} title="Supprimer">
                    <i className="fas fa-trash"></i>
                </button>
                <i className="fas fa-chevron-right text-gray-300 ml-1"></i>
            </div>
        </div>
    );
}

function Stat({ icon, label, value, alert }) {
    return (
        <div className="flex items-center gap-2 text-sm">
            <i className={`fas fa-${icon} text-gray-400 text-xs`}></i>
            <div>
                <div className={`font-semibold ${alert ? 'text-red-600' : 'text-gray-900'}`}>{value}</div>
                <div className="text-[10px] uppercase tracking-wide text-gray-400 leading-none">{label}</div>
            </div>
        </div>
    );
}

function OperatorCreateModal({ onClose, onSave }) {
    const [data, setData] = useState({
        company: '', partnerkey: '', email_management: '', phone: '',
        address: '', color: '#7c3aed', sms_balance: 130, radius: 25,
        is_method_card: 1, is_method_cash: 1, is_method_bill: 1,
    });
    const [accounts, setAccounts] = useState([]);
    useEffect(() => { MyProAPI.accounts().then(d => setAccounts(d.accounts || [])); }, []);
    const set = (k, v) => setData(d => ({ ...d, [k]: v }));

    return (
        <Modal title="Nouvelle centrale" onClose={onClose} size="lg"
            footer={<>
                <button className="btn btn-secondary" onClick={onClose}>Annuler</button>
                <button className="btn btn-primary" onClick={() => onSave(data)}>Créer</button>
            </>}>
            <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
                <Field label="Compte client propriétaire">
                    <Select value={data.account_id} onChange={v => set('account_id', parseInt(v))}
                        options={accounts.map(a => ({ value: a.id, label: `${a.name || a.email} — ${a.company || ''}` }))} />
                </Field>
                <Field label="Nom commercial *">
                    <TextInput value={data.company} onChange={v => set('company', v)} required placeholder="Taxi Lausanne SA" />
                </Field>
                <Field label="Sous-domaine (partnerkey)">
                    <TextInput value={data.partnerkey} onChange={v => set('partnerkey', v.toLowerCase().replace(/[^a-z0-9-]/g, ''))} placeholder="auto-généré depuis le nom" />
                </Field>
                <Field label="Email gestion *">
                    <TextInput type="email" value={data.email_management} onChange={v => set('email_management', v)} required />
                </Field>
                <Field label="Téléphone"><TextInput value={data.phone} onChange={v => set('phone', v)} /></Field>
                <Field label="Téléphone réservation"><TextInput value={data.phone_booking} onChange={v => set('phone_booking', v)} /></Field>
                <div className="md:col-span-2"><Field label="Adresse"><TextInput value={data.address} onChange={v => set('address', v)} /></Field></div>
                <Field label="Canton"><TextInput value={data.canton} onChange={v => set('canton', v)} placeholder="VD" /></Field>
                <Field label="Couleur principale">
                    <input type="color" value={data.color || '#7c3aed'} onChange={e => set('color', e.target.value)}
                           className="input" style={{ height: 42 }} />
                </Field>
                <Field label="Latitude"><TextInput type="number" value={data.latitude} onChange={v => set('latitude', parseFloat(v))} /></Field>
                <Field label="Longitude"><TextInput type="number" value={data.longitude} onChange={v => set('longitude', parseFloat(v))} /></Field>
                <Field label="Rayon (km)"><TextInput type="number" value={data.radius} onChange={v => set('radius', parseInt(v))} /></Field>
                <Field label="SMS de départ"><TextInput type="number" value={data.sms_balance} onChange={v => set('sms_balance', parseInt(v))} /></Field>
                <Field label="Prix base (CHF)"><TextInput type="number" value={data.base_price} onChange={v => set('base_price', parseFloat(v))} /></Field>
                <Field label="Prix par km (CHF)"><TextInput type="number" value={data.price_per_km} onChange={v => set('price_per_km', parseFloat(v))} /></Field>
                <Field label="Carte"><Checkbox value={data.is_method_card} onChange={v => set('is_method_card', v)} label="Paiement carte en ligne" /></Field>
                <Field label="Cash"><Checkbox value={data.is_method_cash} onChange={v => set('is_method_cash', v)} label="Paiement cash au chauffeur" /></Field>
                <Field label="Compte business"><Checkbox value={data.is_method_bill} onChange={v => set('is_method_bill', v)} label="Paiement sur facture" /></Field>
            </div>
        </Modal>
    );
}

// Section card used inside detail tabs
function Section({ icon, iconColor = 'text-violet-600', title, hint, span, children }) {
    const cls = 'card card-section' + (span ? ' ' + span : '');
    return (
        <div className={cls}>
            <div className="card-header">
                <h2>{icon && <i className={`fas fa-${icon} ${iconColor}`}></i>}{title}</h2>
                {hint && <span className="card-hint">{hint}</span>}
            </div>
            <div className="card-body">{children}</div>
        </div>
    );
}

function ToggleRow({ icon, iconColor = 'text-violet-600', title, desc, value, onChange }) {
    return (
        <div className="toggle-row">
            <div className="toggle-info">
                {icon && <i className={`fas fa-${icon} ${iconColor}`}></i>}
                <div>
                    <div className="toggle-title">{title}</div>
                    {desc && <div className="toggle-desc">{desc}</div>}
                </div>
            </div>
            <Checkbox value={value} onChange={onChange} label="" />
        </div>
    );
}

// ────────────────────────────────────────────────────────────────────────
// LogoDropzone : preview + drag&drop + click + suppression
//   value       : r2_key (string|null)
//   onUpload    : async (slot, filename, base64) → { r2_key }
//   onDelete    : async (slot)
//   onChange    : (newKey) → void
//   slot        : 'main' | 'white' | 'stripe' | 'favicon'
//   label       : libellé affiché
//   hint        : texte d'aide sous le libellé
//   dark        : fond noir (pour logos blancs)
//   accept      : pattern accept input file
// ────────────────────────────────────────────────────────────────────────
function LogoDropzone({ value, onUpload, onDelete, onChange, slot, label, hint, dark = false, accept = 'image/*' }) {
    const [busy, setBusy] = useState(false);
    const [dragOver, setDragOver] = useState(false);
    const [err, setErr] = useState('');
    const inputRef = useRef(null);
    const url = value ? `https://pub.files.swissapp.net/${value}` : null;

    async function fileToBase64(file) {
        return new Promise((resolve, reject) => {
            const r = new FileReader();
            r.onload = () => {
                const s = String(r.result);
                const i = s.indexOf(',');
                resolve(i >= 0 ? s.slice(i + 1) : s);
            };
            r.onerror = reject;
            r.readAsDataURL(file);
        });
    }

    async function handleFile(file) {
        if (!file) return;
        if (file.size > 8 * 1024 * 1024) { setErr('Fichier trop volumineux (max 8 Mo)'); return; }
        setErr(''); setBusy(true);
        try {
            const b64 = await fileToBase64(file);
            const res = await onUpload(slot, file.name, b64);
            onChange(res.r2_key);
            toast('Logo enregistré');
        } catch (e) {
            setErr(e.message || 'Erreur upload');
            toast(e.message || 'Erreur upload', 'error');
        } finally { setBusy(false); }
    }

    async function handleDelete() {
        if (!value) return;
        if (!confirm('Supprimer ce logo ?')) return;
        setBusy(true);
        try {
            await onDelete(slot);
            onChange(null);
            toast('Logo supprimé');
        } catch (e) {
            toast(e.message || 'Erreur', 'error');
        } finally { setBusy(false); }
    }

    return (
        <div className={`logo-dz ${dragOver ? 'logo-dz--over' : ''} ${dark ? 'logo-dz--dark' : ''}`}>
            <div className="logo-dz__head">
                <div>
                    <div className="logo-dz__label">{label}</div>
                    {hint && <div className="logo-dz__hint">{hint}</div>}
                </div>
                {value && (
                    <button type="button" className="logo-dz__del" onClick={handleDelete} disabled={busy} title="Supprimer">
                        <i className="fas fa-trash"></i>
                    </button>
                )}
            </div>
            <div className="logo-dz__zone"
                onDragOver={e => { e.preventDefault(); setDragOver(true); }}
                onDragLeave={() => setDragOver(false)}
                onDrop={e => {
                    e.preventDefault(); setDragOver(false);
                    const f = e.dataTransfer.files?.[0]; if (f) handleFile(f);
                }}
                onClick={() => !busy && inputRef.current?.click()}>
                {url ? (
                    <img src={url} alt={label} className="logo-dz__img" />
                ) : (
                    <div className="logo-dz__empty">
                        <i className="fas fa-cloud-upload-alt text-3xl mb-2"></i>
                        <div className="text-sm">{busy ? 'Upload…' : 'Glissez ou cliquez'}</div>
                    </div>
                )}
                {busy && <div className="logo-dz__overlay"><div className="loading-spinner"></div></div>}
                <input ref={inputRef} type="file" accept={accept} style={{ display: 'none' }}
                    onChange={e => { const f = e.target.files?.[0]; e.target.value = ''; if (f) handleFile(f); }} />
            </div>
            {err && <div className="text-xs text-red-600 mt-1">{err}</div>}
        </div>
    );
}

// ----------------------------------------------------------------------------
// CENTRAL MAP PICKER — Leaflet + Google tiles + autocomplete api.maps
// ----------------------------------------------------------------------------
const GOOGLE_TILES = {
    plan:      { url: 'https://mt1.google.com/vt/lyrs=m&hl=fr&gl=ch&x={x}&y={y}&z={z}', label: 'Plan',      attr: '© Google' },
    satellite: { url: 'https://mt1.google.com/vt/lyrs=s&hl=fr&gl=ch&x={x}&y={y}&z={z}', label: 'Satellite', attr: '© Google Satellite' },
    hybrid:    { url: 'https://mt1.google.com/vt/lyrs=y&hl=fr&gl=ch&x={x}&y={y}&z={z}', label: 'Hybride',   attr: '© Google Hybrid' },
};

function CentralMapPicker({ address, latitude, longitude, radius, onChange }) {
    const mapEl = useRef(null);
    const mapRef = useRef(null);
    const tileRef = useRef(null);
    const markerRef = useRef(null);
    const [layer, setLayer] = useState(() => localStorage.getItem('admin_map_type') || 'plan');
    const [addr, setAddr] = useState(address || '');
    const [suggestions, setSuggestions] = useState([]);
    const [openSugg, setOpenSugg] = useState(false);
    const [searching, setSearching] = useState(false);
    const debounceRef = useRef(null);
    const inputRef = useRef(null);

    // Maintenir l'input synchro si props.address change
    useEffect(() => { setAddr(address || ''); }, [address]);

    // Init map
    useEffect(() => {
        if (!mapEl.current || mapRef.current || typeof L === 'undefined') return;
        const initLat = latitude || 46.2044;
        const initLng = longitude || 6.1432;
        const initZoom = Math.min(Math.max(parseInt(radius) || 12, 1), 18);

        const map = L.map(mapEl.current, { zoomControl: true, scrollWheelZoom: true })
            .setView([initLat, initLng], initZoom);

        const t = GOOGLE_TILES[layer] || GOOGLE_TILES.plan;
        tileRef.current = L.tileLayer(t.url, { attribution: t.attr, maxZoom: 20, subdomains: ['mt0','mt1','mt2','mt3'] }).addTo(map);

        markerRef.current = L.marker([initLat, initLng], { draggable: true }).addTo(map);

        markerRef.current.on('dragend', () => {
            const { lat, lng } = markerRef.current.getLatLng();
            onChange({ lat: round6(lat), lng: round6(lng) });
        });

        map.on('zoomend', () => onChange({ radius: map.getZoom() }));
        map.on('click', (e) => {
            markerRef.current.setLatLng(e.latlng);
            onChange({ lat: round6(e.latlng.lat), lng: round6(e.latlng.lng) });
        });

        mapRef.current = map;

        const invalidate = () => map.invalidateSize();
        requestAnimationFrame(invalidate);
        setTimeout(invalidate, 100);
        setTimeout(invalidate, 350);
        setTimeout(invalidate, 800);

        let ro = null;
        if (typeof ResizeObserver !== 'undefined') {
            ro = new ResizeObserver(invalidate);
            ro.observe(mapEl.current);
        }
        window.addEventListener('resize', invalidate);

        return () => {
            window.removeEventListener('resize', invalidate);
            if (ro) ro.disconnect();
        };
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    // Sync props -> marker quand lat/lng changent depuis l'extérieur
    useEffect(() => {
        if (!mapRef.current || !markerRef.current) return;
        if (latitude && longitude) {
            const lat = parseFloat(latitude), lng = parseFloat(longitude);
            markerRef.current.setLatLng([lat, lng]);
        }
    }, [latitude, longitude]);

    // Switch couche
    useEffect(() => {
        if (!mapRef.current) return;
        const t = GOOGLE_TILES[layer] || GOOGLE_TILES.plan;
        if (tileRef.current) mapRef.current.removeLayer(tileRef.current);
        tileRef.current = L.tileLayer(t.url, { attribution: t.attr, maxZoom: 20, subdomains: ['mt0','mt1','mt2','mt3'] }).addTo(mapRef.current);
        localStorage.setItem('admin_map_type', layer);
    }, [layer]);

    function round6(n) { return Math.round(n * 1e6) / 1e6; }

    function searchAddr(q) {
        setAddr(q);
        onChange({ address: q });
        if (debounceRef.current) clearTimeout(debounceRef.current);
        if (!q || q.length < 3) { setSuggestions([]); setOpenSugg(false); return; }
        setSearching(true);
        debounceRef.current = setTimeout(async () => {
            try {
                const r = await MyProAPI.mapsAutocomplete(q);
                setSuggestions(r.predictions || []);
                setOpenSugg(true);
            } catch (e) { setSuggestions([]); }
            finally { setSearching(false); }
        }, 280);
    }

    async function pickSuggestion(s) {
        const label = s.label || s.description || addr;
        setAddr(label);
        setOpenSugg(false);
        try {
            const geo = await MyProAPI.mapsGeocode(label);
            if (geo && geo.lat && geo.lng) {
                const lat = round6(geo.lat), lng = round6(geo.lng);
                onChange({ address: label, lat, lng });
                if (mapRef.current && markerRef.current) {
                    markerRef.current.setLatLng([lat, lng]);
                    mapRef.current.setView([lat, lng], Math.max(mapRef.current.getZoom(), 13));
                }
            } else {
                onChange({ address: label });
            }
        } catch (e) { toast(e.message, 'error'); }
    }

    async function geocodeCurrent() {
        if (!addr || addr.length < 3) return;
        try {
            const geo = await MyProAPI.mapsGeocode(addr);
            if (geo && geo.lat && geo.lng) {
                const lat = round6(geo.lat), lng = round6(geo.lng);
                onChange({ address: addr, lat, lng });
                if (mapRef.current && markerRef.current) {
                    markerRef.current.setLatLng([lat, lng]);
                    mapRef.current.setView([lat, lng], Math.max(mapRef.current.getZoom(), 13));
                }
                toast('Position trouvée');
            } else toast('Aucun résultat', 'error');
        } catch (e) { toast(e.message, 'error'); }
    }

    return (
        <div>
            <div className="flex gap-2 items-end mb-2">
                <div className="flex-1 relative">
                    <label className="block text-xs text-gray-500 mb-1">Adresse de la centrale</label>
                    <input ref={inputRef} type="text" className="input" value={addr}
                           onChange={e => searchAddr(e.target.value)}
                           onFocus={() => suggestions.length && setOpenSugg(true)}
                           onBlur={() => setTimeout(() => setOpenSugg(false), 180)}
                           placeholder="Tapez une adresse (Genève, Paris, Lausanne…)" />
                    {searching && (
                        <i className="fas fa-spinner fa-spin absolute right-3 top-9 text-gray-400"></i>
                    )}
                    {openSugg && suggestions.length > 0 && (
                        <div className="cmp-sugg">
                            {suggestions.map((s, i) => (
                                <div key={s.placeId || s.place_id || i} className="cmp-sugg__item"
                                     onMouseDown={() => pickSuggestion(s)}>
                                    <i className="fas fa-location-dot text-emerald-500"></i>
                                    <div className="min-w-0">
                                        <div className="font-medium truncate">{s.main || s.label}</div>
                                        {s.secondary && <div className="text-xs text-gray-500 truncate">{s.secondary}</div>}
                                    </div>
                                </div>
                            ))}
                        </div>
                    )}
                </div>
                <button className="btn btn-secondary" onClick={geocodeCurrent} type="button" title="Géocoder l'adresse saisie">
                    <i className="fas fa-search-location"></i>
                </button>
            </div>

            <div className="cmp-map-wrap">
                <div ref={mapEl} className="cmp-map" />
                <div className="cmp-layer-switch">
                    {Object.entries(GOOGLE_TILES).map(([id, l]) => (
                        <button key={id} type="button"
                                className={`cmp-layer-switch__btn ${layer === id ? 'active' : ''}`}
                                onClick={() => setLayer(id)}>{l.label}</button>
                    ))}
                </div>
            </div>
            <div className="text-xs text-gray-500 mt-2">
                <i className="fas fa-info-circle mr-1"></i>
                Cliquez sur la carte ou déplacez le marqueur pour ajuster. Le zoom de la carte est sauvegardé dans le champ "Zoom".
            </div>
        </div>
    );
}

function OperatorDetailPage({ id, onBack, onDeleted }) {
    const { data, err, reload } = useResource(() => MyProAPI.operator(id), [id]);
    const [w, setW] = useState(null); // website edits
    const [c, setC] = useState(null); // central edits
    const [saving, setSaving] = useState(false);
    const [confirmDel, setConfirmDel] = useState(false);

    useEffect(() => { if (data) { setW({ ...data.website }); setC({ ...(data.central || {}) }); } }, [data]);

    async function save() {
        setSaving(true);
        try {
            const wDiff = diffFields(data.website, w);
            const cDiff = diffFields(data.central || {}, c);
            if (!Object.keys(wDiff).length && !Object.keys(cDiff).length) { toast('Aucun changement'); setSaving(false); return; }
            await MyProAPI.updateOperator(id, { website: wDiff, central: cDiff });
            toast('Enregistré'); reload();
        } catch (e) { toast(e.message, 'error'); }
        finally { setSaving(false); }
    }

    async function doDelete() {
        try { await MyProAPI.deleteOperator(id); toast('Centrale supprimée'); onDeleted?.(); }
        catch (e) { toast(e.message, 'error'); setConfirmDel(false); }
    }

    if (err) {
        return (
            <div>
                <button className="btn btn-secondary mb-3" onClick={onBack}>
                    <i className="fas fa-arrow-left"></i> Retour
                </button>
                <div className="card text-red-600">{err}</div>
            </div>
        );
    }
    if (!data || !w) {
        return (
            <div>
                <button className="btn btn-secondary mb-3" onClick={onBack}>
                    <i className="fas fa-arrow-left"></i> Retour
                </button>
                <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
            </div>
        );
    }

    const setW2 = (k, v) => setW(s => ({ ...s, [k]: v }));
    const setC2 = (k, v) => setC(s => ({ ...s, [k]: v }));

    const dirty =
        Object.keys(diffFields(data.website, w)).length > 0 ||
        Object.keys(diffFields(data.central || {}, c)).length > 0;

    const color = w.color || c.color || '#7c3aed';
    const initial = (w.company || c.label || '?').trim().charAt(0).toUpperCase();

    return (
        <div>
            {/* Breadcrumb */}
            <div className="flex items-center gap-2 text-sm text-gray-500 mb-3">
                <button className="hover:text-violet-600" onClick={onBack}>
                    <i className="fas fa-arrow-left mr-1"></i> Centrales
                </button>
                <i className="fas fa-chevron-right text-xs text-gray-300"></i>
                <span className="text-gray-900 font-medium">{w.company || c.label}</span>
            </div>

            {/* Header sticky */}
            <div className="card flex items-center gap-4" style={{ padding: '14px 18px' }}>
                <div className="flex items-center justify-center text-white font-bold flex-shrink-0"
                     style={{ width: 52, height: 52, borderRadius: 12, background: color, fontSize: 22 }}>
                    {initial}
                </div>
                <div className="min-w-0 flex-1">
                    <div className="text-lg font-bold truncate">{w.company || c.label}</div>
                    <div className="text-xs text-gray-500 font-mono truncate">app.mypro.ch/{w.partnerkey}/</div>
                </div>
                <div className="flex items-center gap-2 flex-shrink-0">
                    <a href={`https://app.mypro.ch/${w.partnerkey}/`} target="_blank" rel="noopener"
                       className="btn btn-secondary"><i className="fas fa-external-link-alt"></i> Site</a>
                    <button className="btn btn-secondary text-red-600" onClick={() => setConfirmDel(true)}>
                        <i className="fas fa-trash"></i>
                    </button>
                    <button className="btn btn-primary" onClick={save} disabled={saving || !dirty}>
                        {saving ? <span className="spinner-dot"></span> : (dirty ? 'Enregistrer les changements' : 'Tout est à jour')}
                    </button>
                </div>
            </div>

            <div className="mt-4">
            <TabsView tabs={[
                { id: 'general', label: 'Général', icon: 'info-circle', render: () => (
                    <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                        <Section icon="building" title="Identité" iconColor="text-violet-600">
                            <Field label="Nom commercial"><TextInput value={w.company} onChange={v => setW2('company', v)} /></Field>
                            <Field label="Raison sociale"><TextInput value={w.company_name} onChange={v => setW2('company_name', v)} /></Field>
                            <Field label="Clé URL" hint={`app.mypro.ch/${w.partnerkey}/`}><TextInput value={w.partnerkey} disabled /></Field>
                            <Field label="Label centrale (interne)"><TextInput value={c.label} onChange={v => setC2('label', v)} /></Field>
                        </Section>

                        <Section icon="envelope" title="Contacts" iconColor="text-blue-600">
                            <Field label="Email gestion"><TextInput type="email" value={w.email_management} onChange={v => setW2('email_management', v)} /></Field>
                            <Field label="Email commercial"><TextInput type="email" value={w.email_commercial} onChange={v => setW2('email_commercial', v)} /></Field>
                            <Field label="Email alertes"><TextInput type="email" value={w.email_alert} onChange={v => setW2('email_alert', v)} /></Field>
                            <div className="grid grid-cols-2 gap-3">
                                <Field label="Téléphone"><TextInput value={w.phone} onChange={v => setW2('phone', v)} /></Field>
                                <Field label="Téléphone réservation"><TextInput value={w.phone_booking} onChange={v => setW2('phone_booking', v)} /></Field>
                            </div>
                        </Section>

                        <Section icon="map-marker-alt" title="Géolocalisation" iconColor="text-emerald-600" span="lg:col-span-2">
                            <CentralMapPicker
                                address={w.address}
                                latitude={c.latitude}
                                longitude={c.longitude}
                                radius={c.radius}
                                onChange={({ address, lat, lng, radius }) => {
                                    if (address !== undefined) setW2('address', address);
                                    if (lat !== undefined)     setC2('latitude', lat);
                                    if (lng !== undefined)     setC2('longitude', lng);
                                    if (radius !== undefined)  setC2('radius', radius);
                                }}
                            />
                            <div className="grid grid-cols-2 md:grid-cols-4 gap-3 mt-3">
                                <Field label="Canton / Région"><TextInput value={c.canton} onChange={v => setC2('canton', v)} /></Field>
                                <Field label="Latitude"><TextInput type="number" value={c.latitude} onChange={v => setC2('latitude', parseFloat(v))} /></Field>
                                <Field label="Longitude"><TextInput type="number" value={c.longitude} onChange={v => setC2('longitude', parseFloat(v))} /></Field>
                                <Field label="Zoom (1-18)"><TextInput type="number" value={c.radius} onChange={v => setC2('radius', parseInt(v))} /></Field>
                            </div>
                        </Section>

                        <Section icon="power-off" title="Statut" iconColor="text-orange-500" span="lg:col-span-2">
                            <ToggleRow icon="globe" title="Site actif" desc="Le site public et le widget de réservation sont accessibles." value={w.is_active} onChange={v => setW2('is_active', v)} />
                            <ToggleRow icon="ban" iconColor="text-red-500" title="Centrale fermée" desc="Coupe immédiatement les nouvelles réservations." value={w.is_closed} onChange={v => setW2('is_closed', v)} />
                        </Section>
                    </div>
                )},
                { id: 'branding', label: 'Branding', icon: 'palette', render: () => {
                    const upl = (slot, fn, b64) => MyProAPI.uploadWebsiteLogo(w.id, slot, fn, b64);
                    const del = (slot) => MyProAPI.deleteWebsiteLogo(w.id, slot);
                    return (
                    <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                        <Section icon="droplet" title="Couleurs" iconColor="text-pink-500">
                            <Field label="Couleur principale (site public)">
                                <input type="color" value={w.color || '#7c3aed'} onChange={e => setW2('color', e.target.value)} className="input" style={{ height: 42 }} />
                            </Field>
                            <Field label="Couleur centrale (apps)">
                                <input type="color" value={c.color || '#7c3aed'} onChange={e => setC2('color', e.target.value)} className="input" style={{ height: 42 }} />
                            </Field>
                            <ToggleRow icon="car" iconColor="text-amber-600" title="Véhicule sous logo"
                                desc="Affiche un véhicule générique sous le logo principal du widget."
                                value={c.is_logo_car} onChange={v => setC2('is_logo_car', v)} />
                        </Section>
                        <Section icon="image" title="Logotypes" iconColor="text-indigo-500" hint="Glissez-déposez vos logos ou cliquez pour parcourir. Stockés sur api.files.">
                            <div className="grid grid-cols-2 gap-3">
                                <LogoDropzone value={w.logo_main_key}    onChange={v => setW2('logo_main_key', v)}    onUpload={upl} onDelete={del} slot="main"
                                    label="Logo principal" hint="Affiché sur le widget client." />
                                <LogoDropzone value={w.logo_white_key}   onChange={v => setW2('logo_white_key', v)}   onUpload={upl} onDelete={del} slot="white" dark
                                    label="Logo fond blanc (PNG)" hint="Version pour fonds sombres (emails, PDF)." />
                                <LogoDropzone value={w.logo_stripe_key}  onChange={v => setW2('logo_stripe_key', v)}  onUpload={upl} onDelete={del} slot="stripe"
                                    label="Logo Stripe" hint="Affiché sur la page de paiement Stripe." />
                                <LogoDropzone value={w.logo_favicon_key} onChange={v => setW2('logo_favicon_key', v)} onUpload={upl} onDelete={del} slot="favicon"
                                    label="Favicon (PNG)" hint="Icône onglet navigateur." accept="image/png,image/x-icon" />
                            </div>
                        </Section>
                    </div>
                    );
                }},
                { id: 'tarif', label: 'Tarification', icon: 'tags', render: () => (
                    <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                        <Section icon="coins" title="Prix de base" iconColor="text-amber-500">
                            <div className="grid grid-cols-2 gap-3">
                                <Field label="Prix de base (CHF)"><TextInput type="number" value={c.base_price} onChange={v => setC2('base_price', parseFloat(v))} /></Field>
                                <Field label="Prix par km (CHF)"><TextInput type="number" value={c.price_per_km} onChange={v => setC2('price_per_km', parseFloat(v))} /></Field>
                            </div>
                        </Section>
                        <Section icon="percent" title="Commissions" iconColor="text-rose-500">
                            <Field label="% commission chauffeurs" hint="Part prélevée sur chaque course chauffeur."><TextInput type="number" value={w.affiliate_percent_to_pay} onChange={v => setW2('affiliate_percent_to_pay', parseFloat(v))} /></Field>
                            <Field label="% commission inter-centrale" hint="Part rétrocédée pour les courses Adlap Network."><TextInput type="number" value={w.partner_percent_to_pay} onChange={v => setW2('partner_percent_to_pay', parseFloat(v))} /></Field>
                        </Section>
                        <Section icon="clock" title="Délais opérationnels" iconColor="text-cyan-600" span="lg:col-span-2">
                            <div className="grid grid-cols-1 md:grid-cols-3 gap-3">
                                <Field label="Annulation auto (min)" hint="Si non confirmée."><TextInput type="number" value={c.booking_cancellation_delay} onChange={v => setC2('booking_cancellation_delay', parseInt(v))} /></Field>
                                <Field label="Auto-dispatch avant (min)" hint="Avant heure de prise en charge."><TextInput type="number" value={c.autodispatch_minutes_before} onChange={v => setC2('autodispatch_minutes_before', parseInt(v))} /></Field>
                                <Field label="Délai proposal (min)" hint="Temps de réponse chauffeur."><TextInput type="number" value={c.proposal_delay_minute} onChange={v => setC2('proposal_delay_minute', parseInt(v))} /></Field>
                            </div>
                        </Section>
                    </div>
                )},
                { id: 'paiement', label: 'Paiement', icon: 'credit-card', render: () => (
                    <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                        <Section icon="wallet" title="Méthodes acceptées" iconColor="text-emerald-600">
                            <ToggleRow icon="credit-card" title="Carte en ligne" desc="Paiement Stripe à la réservation." value={c.is_method_card} onChange={v => setC2('is_method_card', v)} />
                            <ToggleRow icon="money-bill" iconColor="text-green-600" title="Cash au chauffeur" desc="Paiement direct en espèces." value={c.is_method_cash} onChange={v => setC2('is_method_cash', v)} />
                            <ToggleRow icon="mobile-alt" iconColor="text-blue-600" title="Carte au chauffeur" desc="Terminal de paiement embarqué." value={c.is_method_card_to_driver} onChange={v => setC2('is_method_card_to_driver', v)} />
                            <ToggleRow icon="briefcase" iconColor="text-indigo-600" title="Compte business" desc="Facturation sur compte entreprise." value={c.is_method_bill} onChange={v => setC2('is_method_bill', v)} />
                            <ToggleRow icon="file-invoice" iconColor="text-indigo-400" title="Business light" desc="Avec saisie d'une référence." value={c.is_method_bill_light} onChange={v => setC2('is_method_bill_light', v)} />
                        </Section>
                        <Section icon="cog" title="Comportements" iconColor="text-violet-600">
                            <ToggleRow icon="check-circle" iconColor="text-green-500" title="Validation directe du paiement" value={c.is_method_direct} onChange={v => setC2('is_method_direct', v)} />
                            <ToggleRow icon="eye-slash" iconColor="text-gray-500" title="Masquer prix sur la quittance" value={c.is_hide_receipt_price} onChange={v => setC2('is_hide_receipt_price', v)} />
                            <ToggleRow icon="user-tie" iconColor="text-amber-600" title="Facturation au nom des chauffeurs" desc="Les factures sortent au nom du chauffeur." value={c.is_driver_invoiced} onChange={v => setC2('is_driver_invoiced', v)} />
                        </Section>
                        <Section icon="key" title="API Stripe" iconColor="text-purple-600" span="lg:col-span-2">
                            <Field label="Clé Stripe publique"><TextInput value={c.stripe_public_key} onChange={v => setC2('stripe_public_key', v)} placeholder="pk_live_..." /></Field>
                            <Field label="Clé Stripe privée"><TextInput value={c.stripe_private_key} onChange={v => setC2('stripe_private_key', v)} placeholder="sk_live_..." /></Field>
                        </Section>
                    </div>
                )},
                { id: 'banque', label: 'Banque', icon: 'university', render: () => (
                    <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                        <Section icon="university" title="Établissement bancaire" iconColor="text-blue-600">
                            <Field label="Nom de la banque"><TextInput value={w.bank_name} onChange={v => setW2('bank_name', v)} /></Field>
                            <Field label="Adresse"><TextInput value={w.bank_street} onChange={v => setW2('bank_street', v)} /></Field>
                        </Section>
                        <Section icon="hashtag" title="Coordonnées" iconColor="text-emerald-600">
                            <Field label="IBAN"><TextInput value={w.bank_iban} onChange={v => setW2('bank_iban', v)} /></Field>
                            <Field label="SWIFT / BIC"><TextInput value={w.bank_swift} onChange={v => setW2('bank_swift', v)} /></Field>
                        </Section>
                    </div>
                )},
                { id: 'modules', label: 'Modules', icon: 'puzzle-piece', render: () => (
                    <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                        <Section icon="car" title="Modules réservation" iconColor="text-violet-600">
                            <ToggleRow icon="baby" iconColor="text-pink-500" title="Siège bébé" desc="Option commandable à la réservation." value={w.is_baby_seat_enabled} onChange={v => setW2('is_baby_seat_enabled', v)} />
                            <ToggleRow icon="hourglass-half" iconColor="text-amber-500" title="Forfaits horaires (disposition)" desc="Mise à disposition à l'heure." value={w.is_disposition_enabled} onChange={v => setW2('is_disposition_enabled', v)} />
                            <ToggleRow icon="exchange-alt" iconColor="text-blue-500" title="Aller-retour" desc="Réservation aller + retour en une fois." value={w.is_return_enabled} onChange={v => setW2('is_return_enabled', v)} />
                        </Section>
                        <Section icon="bell" title="Communication" iconColor="text-orange-500">
                            <ToggleRow icon="sms" iconColor="text-green-500" title="Envoi SMS" desc="Notifications clients par SMS." value={w.is_sms_enabled} onChange={v => setW2('is_sms_enabled', v)} />
                            <ToggleRow icon="paper-plane" iconColor="text-cyan-500" title="Système push" desc="Notifications push chauffeurs." value={w.is_push_system} onChange={v => setW2('is_push_system', v)} />
                            <ToggleRow icon="users" iconColor="text-indigo-500" title="Inclure chauffeurs sans GPS" desc="Au dispatch, considère tous les chauffeurs actifs." value={w.is_select_all_drivers} onChange={v => setW2('is_select_all_drivers', v)} />
                        </Section>
                        <Section icon="network-wired" title="Adlap Network" iconColor="text-purple-600" span="lg:col-span-2">
                            <ToggleRow icon="upload" iconColor="text-blue-500" title="Diffuser ses courses" desc="Courses partagées aux autres centrales." value={c.is_pushed_to_adlap_network} onChange={v => setC2('is_pushed_to_adlap_network', v)} />
                            <ToggleRow icon="download" iconColor="text-green-500" title="Recevoir des courses" desc="Reçoit les overflows des autres centrales." value={c.is_pushed_to_adlap_network_receive} onChange={v => setC2('is_pushed_to_adlap_network_receive', v)} />
                            <ToggleRow icon="ban" iconColor="text-red-500" title="Auto-annulation" desc="Annule les courses non confirmées dans les délais." value={c.is_autocancellation} onChange={v => setC2('is_autocancellation', v)} />
                            <ToggleRow icon="external-link-alt" iconColor="text-gray-500" title="Widget : nouvelle fenêtre" desc="Ouvre le widget dans un onglet séparé." value={c.is_widget_open_in_new_window} onChange={v => setC2('is_widget_open_in_new_window', v)} />
                            <div className="pt-2 border-t border-gray-100">
                                <Field label="Priorité ACN" hint="Ordre de priorité sur le réseau Adlap (plus bas = prioritaire).">
                                    <TextInput type="number" value={c.fee_from_central_priority} onChange={v => setC2('fee_from_central_priority', parseInt(v))} />
                                </Field>
                            </div>
                        </Section>
                    </div>
                )},
                { id: 'sms', label: 'SMS', icon: 'sms', render: () => (
                    <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                        <Section icon="wallet" title="Solde" iconColor="text-emerald-600">
                            <Field label="Solde SMS actuel" hint={`${w.sms_balance || 0} SMS restants.`}><TextInput type="number" value={w.sms_balance} onChange={v => setW2('sms_balance', parseInt(v))} /></Field>
                            <Field label="Seuil d'alerte" hint="Notifie la centrale en-dessous de ce solde."><TextInput type="number" value={w.sms_alert} onChange={v => setW2('sms_alert', parseInt(v))} /></Field>
                        </Section>
                        <Section icon="signature" title="Expéditeur" iconColor="text-blue-600">
                            <Field label="Nom expéditeur" hint="11 caractères maximum (alphanumérique).">
                                <TextInput value={w.sms_sender} onChange={v => setW2('sms_sender', v.slice(0, 11))} />
                            </Field>
                        </Section>
                    </div>
                )},
            ]} />
            </div>

            {confirmDel && (
                <ConfirmDialog title="Supprimer la centrale" danger
                    message={`La centrale "${w.company || c.label}" et son site (${w.partnerkey}) seront supprimés. Cette action est irréversible.`}
                    confirmLabel="Supprimer définitivement"
                    onCancel={() => setConfirmDel(false)}
                    onConfirm={doDelete} />
            )}
        </div>
    );
}

// ============================================================================
// BOOKINGS CROSS-CENTRALES
// ============================================================================
// ============================================================================
// DIFFUSION — flux temps réel cross-centrales
// ============================================================================
const FEED_TYPES = [
    { id: 'booking',  label: 'Réservations', icon: 'plus-circle',     color: 'violet' },
    { id: 'dispatch', label: 'Dispatchs',    icon: 'taxi',            color: 'indigo' },
    { id: 'complete', label: 'Terminées',    icon: 'flag-checkered',  color: 'emerald' },
    { id: 'cancel',   label: 'Annulations',  icon: 'ban',             color: 'red' },
    { id: 'no_show',  label: 'No-show',      icon: 'user-slash',      color: 'orange' },
    { id: 'payment',  label: 'Paiements',    icon: 'credit-card',     color: 'green' },
    { id: 'sms',      label: 'SMS',          icon: 'sms',             color: 'sky' },
];

const COLOR_BG = {
    violet:  'bg-violet-100 text-violet-700',
    indigo:  'bg-indigo-100 text-indigo-700',
    emerald: 'bg-emerald-100 text-emerald-700',
    red:     'bg-red-100 text-red-700',
    orange:  'bg-orange-100 text-orange-700',
    green:   'bg-green-100 text-green-700',
    sky:     'bg-sky-100 text-sky-700',
    teal:    'bg-teal-100 text-teal-700',
    amber:   'bg-amber-100 text-amber-700',
};

function relTime(iso) {
    if (!iso) return '';
    const t = new Date(iso.includes('T') ? iso : iso.replace(' ', 'T') + 'Z').getTime();
    if (isNaN(t)) return iso;
    const s = Math.max(0, (Date.now() - t) / 1000);
    if (s < 60)    return `il y a ${Math.floor(s)}s`;
    if (s < 3600)  return `il y a ${Math.floor(s/60)}min`;
    if (s < 86400) return `il y a ${Math.floor(s/3600)}h`;
    return new Date(t).toLocaleString('fr-CH', { dateStyle: 'short', timeStyle: 'short' });
}

function PageDiffusion() {
    const [centrals, setCentrals]   = useState([]);
    const [centralId, setCentralId] = useState('');
    const [activeTypes, setActiveTypes] = useState(() => new Set(FEED_TYPES.map(t => t.id)));
    const [events, setEvents] = useState([]);
    const [paused, setPaused] = useState(false);
    const [loading, setLoading] = useState(true);
    const [err, setErr] = useState(null);
    const [lastFetch, setLastFetch] = useState(null);
    const seenIds = React.useRef(new Set());
    const [, force] = useState(0);

    useEffect(() => {
        MyProAPI.operators().then(d => setCentrals(d.operators || []));
    }, []);

    // Reset à chaque changement de filtre centrale
    useEffect(() => {
        seenIds.current = new Set();
        setEvents([]);
        setLoading(true);
    }, [centralId]);

    // Tick relatif "il y a Xs"
    useEffect(() => {
        const id = setInterval(() => force(n => n + 1), 1000);
        return () => clearInterval(id);
    }, []);

    // Polling
    useEffect(() => {
        let cancelled = false;
        async function fetchOnce() {
            try {
                const params = { limit: 80 };
                if (centralId) params.central_id = centralId;
                const d = await MyProAPI.feed(params);
                if (cancelled) return;
                const list = d.feed || [];
                const incoming = [];
                for (const ev of list) {
                    const key = `${ev.type}:${ev.booking_id || ''}:${ev.ts}:${ev.title}`;
                    if (!seenIds.current.has(key)) {
                        seenIds.current.add(key);
                        incoming.push({ ...ev, _key: key, _new: true });
                    }
                }
                if (incoming.length) {
                    setEvents(prev => {
                        const merged = [...incoming, ...prev].slice(0, 200);
                        return merged;
                    });
                    setTimeout(() => {
                        if (cancelled) return;
                        setEvents(prev => prev.map(e => ({ ...e, _new: false })));
                    }, 1500);
                }
                setErr(null);
                setLastFetch(new Date());
            } catch (e) {
                if (!cancelled) setErr(e.message || 'Erreur de chargement');
            } finally {
                if (!cancelled) setLoading(false);
            }
        }
        fetchOnce();
        if (paused) return () => { cancelled = true; };
        const id = setInterval(fetchOnce, 5000);
        return () => { cancelled = true; clearInterval(id); };
    }, [centralId, paused]);

    function toggleType(id) {
        setActiveTypes(prev => {
            const next = new Set(prev);
            if (next.has(id)) next.delete(id); else next.add(id);
            return next;
        });
    }

    const filtered = events.filter(e => activeTypes.has(e.type));
    const stats = {};
    for (const t of FEED_TYPES) stats[t.id] = 0;
    for (const e of events) if (stats[e.type] != null) stats[e.type]++;

    return (
        <div>
            <div className="flex items-center justify-between mb-4 flex-wrap gap-3">
                <div>
                    <h1 className="text-2xl font-bold flex items-center gap-2">
                        <i className="fas fa-tower-broadcast text-violet-600"></i> Diffusion
                        <span className={`ml-2 inline-flex items-center gap-1.5 text-xs px-2 py-1 rounded-full ${paused ? 'bg-gray-100 text-gray-600' : 'bg-emerald-100 text-emerald-700'}`}>
                            <span className={`w-2 h-2 rounded-full ${paused ? 'bg-gray-400' : 'bg-emerald-500 animate-pulse'}`}></span>
                            {paused ? 'En pause' : 'En direct'}
                        </span>
                    </h1>
                    <p className="text-sm text-gray-500">
                        Flux temps réel des événements
                        {centralId && centrals.find(c => c.id === parseInt(centralId)) && (
                            <> · <span className="font-medium text-gray-700">{centrals.find(c => c.id === parseInt(centralId)).label || centrals.find(c => c.id === parseInt(centralId)).company}</span></>
                        )}
                        {lastFetch && <> · maj {lastFetch.toLocaleTimeString('fr-CH')}</>}
                    </p>
                </div>
                <div className="flex items-center gap-2">
                    <select value={centralId} onChange={e => setCentralId(e.target.value)} className="input" style={{ minWidth: 220 }}>
                        <option value="">Toutes les centrales</option>
                        {centrals.map(c =>
                            <option key={c.id} value={c.id}>{c.label || c.company}</option>
                        )}
                    </select>
                    <button className="btn" onClick={() => setPaused(p => !p)}>
                        <i className={`fas fa-${paused ? 'play' : 'pause'} mr-2`}></i>
                        {paused ? 'Reprendre' : 'Pause'}
                    </button>
                </div>
            </div>

            {/* Type filter chips */}
            <div className="flex flex-wrap gap-2 mb-4">
                {FEED_TYPES.map(t => {
                    const active = activeTypes.has(t.id);
                    return (
                        <button key={t.id} onClick={() => toggleType(t.id)}
                            className={`inline-flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition ${active ? COLOR_BG[t.color] + ' border-transparent' : 'bg-white text-gray-500 border-gray-200 hover:bg-gray-50'}`}>
                            <i className={`fas fa-${t.icon}`}></i>
                            {t.label}
                            <span className={`ml-1 text-[10px] font-bold ${active ? 'opacity-80' : 'opacity-50'}`}>{stats[t.id] || 0}</span>
                        </button>
                    );
                })}
            </div>

            {err && <div className="card text-red-600 mb-3"><i className="fas fa-exclamation-triangle mr-2"></i>{err}</div>}
            {loading && !events.length && <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>}
            {!loading && !filtered.length && !err && (
                <div className="card text-center text-gray-400 py-10">
                    <i className="fas fa-satellite-dish text-3xl mb-3 block"></i>
                    Aucun événement pour l'instant. Le flux se mettra à jour automatiquement.
                </div>
            )}

            <div className="space-y-2">
                {filtered.map(e => (
                    <div key={e._key} className={`card flex items-start gap-3 transition-all ${e._new ? 'ring-2 ring-violet-300 bg-violet-50/40' : ''}`}>
                        <div className={`w-10 h-10 rounded-full flex items-center justify-center shrink-0 ${COLOR_BG[e.color] || 'bg-gray-100 text-gray-600'}`}>
                            <i className={`fas fa-${e.icon}`}></i>
                        </div>
                        <div className="flex-1 min-w-0">
                            <div className="flex items-start justify-between gap-3">
                                <div className="font-semibold text-gray-800 truncate">{e.title}</div>
                                <div className="text-xs text-gray-400 whitespace-nowrap" title={e.ts}>{relTime(e.ts)}</div>
                            </div>
                            {e.desc && <div className="text-sm text-gray-600 mt-0.5 truncate">{e.desc}</div>}
                            <div className="flex items-center gap-2 mt-1.5 text-xs text-gray-400 flex-wrap">
                                {e.central_label && (
                                    <span className="inline-flex items-center gap-1"><i className="fas fa-building"></i>{e.central_label}</span>
                                )}
                                {e.amount != null && e.amount !== 0 && (
                                    <span className="inline-flex items-center gap-1"><i className="fas fa-coins"></i>{e.amount} {e.currency || ''}</span>
                                )}
                                {e.sms_count > 0 && (
                                    <span className="inline-flex items-center gap-1"><i className="fas fa-layer-group"></i>{e.sms_count} SMS</span>
                                )}
                                {e.status && e.type === 'sms' && (
                                    <span className="inline-flex items-center gap-1"><i className="fas fa-circle-info"></i>{e.status}</span>
                                )}
                            </div>
                        </div>
                    </div>
                ))}
            </div>
        </div>
    );
}

function PageBookings() {
    const [search, setSearch] = useState('');
    const [status, setStatus] = useState('');
    const [centralId, setCentralId] = useState('');
    const [centrals, setCentrals] = useState([]);
    const [selectedId, setSelectedId] = useState(null);
    useEffect(() => { MyProAPI.operators().then(d => setCentrals(d.operators || [])); }, []);

    const { data, err, reload } = useResource(() => MyProAPI.bookings({
        ...(search ? { q: search } : {}),
        ...(status ? { status } : {}),
        ...(centralId ? { central_id: centralId } : {}),
    }), [search, status, centralId]);

    if (selectedId) {
        return <BookingDetailPage id={selectedId}
            onBack={() => { setSelectedId(null); reload(); }}
            onChanged={reload} />;
    }

    return (
        <div>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Réservations</h1>
                    <div className="page-subtitle">Toutes les courses, toutes centrales confondues.</div>
                </div>
            </div>
            <div className="toolbar">
                <input className="search-input" placeholder="Rechercher (réf, email, nom, mobile)…"
                       value={search} onChange={e => setSearch(e.target.value)} />
                <select className="input" style={{ maxWidth: 200 }} value={status} onChange={e => setStatus(e.target.value)}>
                    <option value="">Tous statuts</option>
                    <option value="pending">En attente</option>
                    <option value="assigned">Assignées</option>
                    <option value="completed">Terminées</option>
                    <option value="cancelled">Annulées</option>
                    <option value="no-show">No-show</option>
                </select>
                <select className="input" style={{ maxWidth: 240 }} value={centralId} onChange={e => setCentralId(e.target.value)}>
                    <option value="">Toutes centrales</option>
                    {centrals.map(c => <option key={c.central_id} value={c.central_id}>{c.company}</option>)}
                </select>
            </div>
            {err && <div className="card text-red-600 mb-3">{err}</div>}
            {!data ? <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
             : (data.bookings || []).length === 0 ? <div className="card text-center text-gray-500 py-10">Aucune course</div>
             : (
                <div className="card" style={{ padding: 0, overflow: 'auto' }}>
                    <table className="data">
                        <thead><tr>
                            <th>Réf</th><th>Date</th><th>Centrale</th><th>Client</th>
                            <th>Trajet</th><th>Prix</th><th>Paiement</th><th>Statut</th>
                        </tr></thead>
                        <tbody>
                            {data.bookings.map(b => (
                                <tr key={b.id} className="row-link" onClick={() => setSelectedId(b.id)}>
                                    <td><strong>{b.reference || '#' + b.id}</strong></td>
                                    <td className="text-xs whitespace-nowrap">{(b.dated || '').replace('T', ' ').slice(0, 16)}</td>
                                    <td className="text-sm">{b.central_label}</td>
                                    <td className="text-sm">
                                        <div>{((b.customer_firstname || '') + ' ' + (b.customer_lastname || '')).trim() || '—'}</div>
                                        <div className="text-xs text-gray-500">{b.customer_mobile}</div>
                                    </td>
                                    <td className="text-xs max-w-xs">
                                        <div className="truncate">↑ {b.origin_address}</div>
                                        <div className="truncate">↓ {b.destination_address}</div>
                                    </td>
                                    <td className="whitespace-nowrap">{(b.price || 0)} {b.currency || 'CHF'}</td>
                                    <td className="text-xs">
                                        {b.payment_method || '—'}
                                        {b.is_paid ? <span className="badge badge-success ml-1">Payé</span> : null}
                                    </td>
                                    <td>
                                        {b.cancelled ? <span className="badge badge-danger">Annulée</span>
                                         : b.is_no_show ? <span className="badge badge-warn">No-show</span>
                                         : b.is_completed ? <span className="badge badge-success">Terminée</span>
                                         : b.selected_driver_id ? <span className="badge badge-info">Assignée</span>
                                         : <span className="badge badge-muted">En attente</span>}
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            )}
        </div>
    );
}

// ============================================================================
// DRIVERS CROSS-CENTRALES
// ============================================================================
function PageDrivers() {
    const [search, setSearch] = useState('');
    const [centralId, setCentralId] = useState('');
    const [centrals, setCentrals] = useState([]);
    const [selectedId, setSelectedId] = useState(null);
    useEffect(() => { MyProAPI.operators().then(d => setCentrals(d.operators || [])); }, []);

    const { data, err, reload } = useResource(() => MyProAPI.drivers({
        ...(search ? { q: search } : {}),
        ...(centralId ? { central_id: centralId } : {}),
    }), [search, centralId]);

    if (selectedId) {
        return <DriverDetailPage id={selectedId}
            onBack={() => { setSelectedId(null); reload(); }}
            onChanged={reload} />;
    }

    return (
        <div>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Chauffeurs</h1>
                    <div className="page-subtitle">Tous les chauffeurs, toutes centrales confondues.</div>
                </div>
            </div>
            <div className="toolbar">
                <input className="search-input" placeholder="Rechercher (nom, email, mobile)…"
                       value={search} onChange={e => setSearch(e.target.value)} />
                <select className="input" style={{ maxWidth: 240 }} value={centralId} onChange={e => setCentralId(e.target.value)}>
                    <option value="">Toutes centrales</option>
                    {centrals.map(c => <option key={c.central_id} value={c.central_id}>{c.company}</option>)}
                </select>
            </div>
            {err && <div className="card text-red-600 mb-3">{err}</div>}
            {!data ? <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
             : (data.drivers || []).length === 0 ? <div className="card text-center text-gray-500 py-10">Aucun chauffeur</div>
             : (
                <div className="card" style={{ padding: 0, overflow: 'auto' }}>
                    <table className="data">
                        <thead><tr>
                            <th></th><th>Nom</th><th>Centrale</th><th>Contact</th>
                            <th>Courses</th><th>Actif</th><th>Auto</th><th>Star</th><th>Online</th>
                        </tr></thead>
                        <tbody>
                            {data.drivers.map(d => (
                                <tr key={d.id} className="row-link" onClick={() => setSelectedId(d.id)}>
                                    <td>{d.is_star ? <i className="fas fa-star text-yellow-500"></i> : null}</td>
                                    <td><strong>{d.firstname} {d.lastname}</strong></td>
                                    <td className="text-sm">{d.central_label || '—'}</td>
                                    <td className="text-sm">
                                        <div>{d.email}</div>
                                        <div className="text-xs text-gray-500">{d.mobile}</div>
                                    </td>
                                    <td><span className="badge badge-info">{d.bookings_count}</span></td>
                                    <td>{d.is_active ? <span className="badge badge-success">Oui</span> : <span className="badge badge-muted">Non</span>}</td>
                                    <td>{d.is_automatic ? <span className="badge badge-success">Oui</span> : <span className="badge badge-muted">Non</span>}</td>
                                    <td>{d.is_star ? <span className="badge badge-warn">★</span> : <span className="text-gray-300">—</span>}</td>
                                    <td>{d.is_online ? <span className="badge badge-success">●</span> : <span className="text-gray-300">○</span>}</td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            )}
        </div>
    );
}

// ============================================================================
// PARTNERS
// ============================================================================
function PagePartners() {
    const { data, err, reload } = useResource(() => MyProAPI.partners(), []);
    const [editing, setEditing] = useState(null);
    const [confirm, setConfirm] = useState(null);

    async function save() {
        try {
            if (editing.id) await MyProAPI.updatePartner(editing.id, stripMeta(editing));
            else await MyProAPI.createPartner(editing);
            toast('Enregistré'); setEditing(null); reload();
        } catch (e) { toast(e.message, 'error'); }
    }
    async function doDelete(id) {
        try { await MyProAPI.deletePartner(id); toast('Supprimé'); setConfirm(null); reload(); }
        catch (e) { toast(e.message, 'error'); }
    }

    return (
        <div>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Partenaires (apporteurs d'affaires)</h1>
                    <div className="page-subtitle">Hôtels, conciergeries, plateformes qui apportent des réservations contre commission.</div>
                </div>
                <button className="btn btn-primary" onClick={() => setEditing({ commission_type: 'percent', commission_value: 10, is_active: 1, color: '#7c3aed' })}>
                    <i className="fas fa-plus"></i> Nouveau partenaire
                </button>
            </div>
            {err && <div className="card text-red-600 mb-3">{err}</div>}
            {!data ? <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
             : (data.partners || []).length === 0 ? <div className="card text-center text-gray-500 py-10">Aucun partenaire</div>
             : (
                <div className="card" style={{ padding: 0, overflow: 'auto' }}>
                    <table className="data">
                        <thead><tr>
                            <th>Label</th><th>Slug</th><th>Type</th><th>Contact</th>
                            <th>Commission</th><th>Courses</th><th>Statut</th><th></th>
                        </tr></thead>
                        <tbody>
                            {data.partners.map(p => (
                                <tr key={p.id}>
                                    <td>
                                        <div className="font-semibold flex items-center gap-2">
                                            {p.color && <span className="inline-block w-3 h-3 rounded" style={{ background: p.color }}></span>}
                                            {p.label}
                                        </div>
                                    </td>
                                    <td className="font-mono text-xs">{p.slug}</td>
                                    <td className="text-sm">{p.company_type || '—'}</td>
                                    <td className="text-sm">
                                        <div>{p.contact_name}</div>
                                        <div className="text-xs text-gray-500">{p.contact_email}</div>
                                    </td>
                                    <td>
                                        <strong>{p.commission_value}{p.commission_type === 'percent' ? '%' : ' CHF'}</strong>
                                    </td>
                                    <td><span className="badge badge-info">{p.bookings_count_live || 0}</span></td>
                                    <td>
                                        {p.is_active
                                            ? (p.is_validated ? <span className="badge badge-success">Validé</span> : <span className="badge badge-warn">En attente</span>)
                                            : <span className="badge badge-muted">Inactif</span>}
                                    </td>
                                    <td className="whitespace-nowrap">
                                        <button className="text-gray-500 hover:text-violet-600 px-2" onClick={() => setEditing(p)}><i className="fas fa-pen"></i></button>
                                        <button className="text-gray-500 hover:text-red-600 px-2" onClick={() => setConfirm(p)}><i className="fas fa-trash"></i></button>
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            )}
            {editing && <PartnerEditModal partner={editing} setPartner={setEditing} onClose={() => setEditing(null)} onSave={save} />}
            {confirm && (
                <ConfirmDialog title="Supprimer le partenaire" danger
                    message={`Le partenaire "${confirm.label}" sera supprimé.`}
                    confirmLabel="Supprimer"
                    onCancel={() => setConfirm(null)}
                    onConfirm={() => doDelete(confirm.id)} />
            )}
        </div>
    );
}

function PartnerEditModal({ partner, setPartner, onClose, onSave }) {
    const set = (k, v) => setPartner(p => ({ ...p, [k]: v }));
    return (
        <Modal title={partner.id ? 'Modifier le partenaire' : 'Nouveau partenaire'} onClose={onClose} size="lg"
            footer={<>
                <button className="btn btn-secondary" onClick={onClose}>Annuler</button>
                <button className="btn btn-primary" onClick={onSave}>Enregistrer</button>
            </>}>
            <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
                <Field label="Libellé *"><TextInput value={partner.label} onChange={v => set('label', v)} required placeholder="Hôtel des Bergues" /></Field>
                <Field label="Slug"><TextInput value={partner.slug} onChange={v => set('slug', v.toLowerCase().replace(/[^a-z0-9-]/g, ''))} placeholder="auto si vide" /></Field>
                <Field label="Type d'entreprise"><TextInput value={partner.company_type} onChange={v => set('company_type', v)} placeholder="Hôtel, Conciergerie, ..." /></Field>
                <Field label="Couleur">
                    <input type="color" value={partner.color || '#7c3aed'} onChange={e => set('color', e.target.value)} className="input" style={{ height: 42 }} />
                </Field>
                <div className="md:col-span-2"><Field label="Description"><TextArea value={partner.description} onChange={v => set('description', v)} /></Field></div>
                <Field label="Contact - Nom"><TextInput value={partner.contact_name} onChange={v => set('contact_name', v)} /></Field>
                <Field label="Contact - Email *"><TextInput type="email" value={partner.contact_email} onChange={v => set('contact_email', v)} required /></Field>
                <Field label="Contact - Téléphone"><TextInput value={partner.contact_phone} onChange={v => set('contact_phone', v)} /></Field>
                <Field label="Site web"><TextInput value={partner.website_url} onChange={v => set('website_url', v)} placeholder="https://..." /></Field>
                <div className="md:col-span-2"><Field label="Adresse"><TextInput value={partner.address} onChange={v => set('address', v)} /></Field></div>
                <Field label="Type de commission">
                    <Select value={partner.commission_type} onChange={v => set('commission_type', v)}
                        options={[{ value: 'percent', label: 'Pourcentage (%)' }, { value: 'amount', label: 'Montant fixe (CHF)' }]}
                        placeholder="" />
                </Field>
                <Field label="Valeur commission"><TextInput type="number" value={partner.commission_value} onChange={v => set('commission_value', parseFloat(v))} /></Field>
                <Field label="Commission min"><TextInput type="number" value={partner.commission_min} onChange={v => set('commission_min', parseFloat(v))} /></Field>
                <Field label="Commission max (0=illimité)"><TextInput type="number" value={partner.commission_max} onChange={v => set('commission_max', parseFloat(v))} /></Field>
                <Field label="Rayon géo (km)"><TextInput type="number" value={partner.geo_radius_km} onChange={v => set('geo_radius_km', parseInt(v))} /></Field>
                <Field label="IBAN paiement"><TextInput value={partner.payment_iban} onChange={v => set('payment_iban', v)} /></Field>
                <Field label="Actif"><Checkbox value={partner.is_active} onChange={v => set('is_active', v)} label="Partenaire actif" /></Field>
                <Field label="Validé"><Checkbox value={partner.is_validated} onChange={v => set('is_validated', v)} label="Validé par admin" /></Field>
            </div>
        </Modal>
    );
}

// ============================================================================
// SMS
// ============================================================================
function PageSms() {
    return (
        <div>
            <div className="page-header">
                <div>
                    <h1 className="page-title">SMS</h1>
                    <div className="page-subtitle">Consommation et recharges SMS, toutes centrales confondues.</div>
                </div>
            </div>
            <TabsView tabs={[
                { id: 'history', label: 'Historique', icon: 'history', render: () => <SmsHistory /> },
                { id: 'orders',  label: 'Recharges',  icon: 'shopping-cart', render: () => <SmsOrders /> },
            ]} />
        </div>
    );
}

function SmsHistory() {
    const [centralId, setCentralId] = useState('');
    const [centrals, setCentrals] = useState([]);
    useEffect(() => { MyProAPI.operators().then(d => setCentrals(d.operators || [])); }, []);
    const { data, err } = useResource(() => MyProAPI.sms(centralId ? { central_id: centralId } : {}), [centralId]);
    return (
        <div>
            <div className="toolbar">
                <select className="input" style={{ maxWidth: 240 }} value={centralId} onChange={e => setCentralId(e.target.value)}>
                    <option value="">Toutes centrales</option>
                    {centrals.map(c => <option key={c.central_id} value={c.central_id}>{c.company}</option>)}
                </select>
            </div>
            {err && <div className="card text-red-600 mb-3">{err}</div>}
            {!data ? <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
             : (data.sms || []).length === 0 ? <div className="card text-center text-gray-500 py-10">Aucun SMS</div>
             : (
                <div className="card" style={{ padding: 0, overflow: 'auto' }}>
                    <table className="data">
                        <thead><tr>
                            <th>Date</th><th>Centrale</th><th>De</th><th>Vers</th>
                            <th>Message</th><th>Qté</th><th>Statut</th>
                        </tr></thead>
                        <tbody>
                            {data.sms.map(s => (
                                <tr key={s.id}>
                                    <td className="text-xs whitespace-nowrap">{s.created}</td>
                                    <td className="text-sm">{s.central_label}</td>
                                    <td className="text-xs">{s.sms_from || '—'}</td>
                                    <td className="text-xs">{s.sms_to || '—'}</td>
                                    <td className="text-xs max-w-xs truncate">{s.message}</td>
                                    <td>{s.sms_count}</td>
                                    <td>
                                        <span className={`badge ${s.status === 'delivered' || s.status === 'sent' ? 'badge-success'
                                            : s.status === 'failed' ? 'badge-danger' : 'badge-warn'}`}>{s.status}</span>
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            )}
        </div>
    );
}

function SmsOrders() {
    const { data, err } = useResource(() => MyProAPI.smsOrders(), []);
    return (
        <div>
            {err && <div className="card text-red-600 mb-3">{err}</div>}
            {!data ? <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
             : (data.orders || []).length === 0 ? <div className="card text-center text-gray-500 py-10">Aucune recharge</div>
             : (
                <div className="card" style={{ padding: 0, overflow: 'auto' }}>
                    <table className="data">
                        <thead><tr>
                            <th>Date</th><th>Site</th><th>Centrale</th><th>Pack</th><th>Statut</th>
                        </tr></thead>
                        <tbody>
                            {data.orders.map(o => (
                                <tr key={o.id}>
                                    <td className="text-xs whitespace-nowrap">{o.created}</td>
                                    <td className="text-sm">{o.website_company}</td>
                                    <td className="text-sm">{o.central_label}</td>
                                    <td>{o.sms_count} SMS</td>
                                    <td>
                                        <span className={`badge ${o.is_payed ? 'badge-success' : 'badge-warn'}`}>{o.is_payed ? 'Payé' : 'En attente'}</span>
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            )}
        </div>
    );
}

// ============================================================================
// COMMISSIONS
// ============================================================================
function PageCommissions() {
    const [status, setStatus] = useState('');
    const { data, err } = useResource(() => MyProAPI.commissions(status ? { status } : {}), [status]);
    return (
        <div>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Commissions</h1>
                    <div className="page-subtitle">Commissions dues / payées aux partenaires apporteurs.</div>
                </div>
            </div>
            <div className="toolbar">
                <select className="input" style={{ maxWidth: 200 }} value={status} onChange={e => setStatus(e.target.value)}>
                    <option value="">Tous statuts</option>
                    <option value="earned">À payer</option>
                    <option value="paid">Payées</option>
                    <option value="cancelled">Annulées</option>
                </select>
            </div>
            {data?.note && <div className="card mb-3 text-amber-800 bg-amber-50 border-amber-200">{data.note}</div>}
            {err && <div className="card text-red-600 mb-3">{err}</div>}
            {!data ? <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
             : (data.commissions || []).length === 0 ? <div className="card text-center text-gray-500 py-10">Aucune commission</div>
             : (
                <div className="card" style={{ padding: 0, overflow: 'auto' }}>
                    <table className="data">
                        <thead><tr>
                            <th>Date</th><th>Partenaire</th><th>Réservation</th>
                            <th>Montant course</th><th>Commission</th><th>Statut</th>
                        </tr></thead>
                        <tbody>
                            {data.commissions.map(c => (
                                <tr key={c.id}>
                                    <td className="text-xs">{c.created}</td>
                                    <td><strong>{c.partner_label}</strong></td>
                                    <td className="font-mono text-xs">{c.booking_reference || '#' + c.booking_id}</td>
                                    <td>{c.booking_price} CHF</td>
                                    <td><strong>{c.commission_amount} CHF</strong></td>
                                    <td>
                                        {c.status === 'paid' ? <span className="badge badge-success">Payée</span>
                                         : c.status === 'earned' ? <span className="badge badge-warn">À payer</span>
                                         : <span className="badge badge-muted">{c.status}</span>}
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            )}
        </div>
    );
}

// ============================================================================
// SITES INTERNETS (générateur)
// ============================================================================
function PageSites() {
    return (
        <div>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Sites internets</h1>
                    <div className="page-subtitle">Générateur de sites de présentation pour chaque centrale.</div>
                </div>
            </div>
            <div className="card">
                <div className="flex items-start gap-4">
                    <div className="w-12 h-12 rounded-lg bg-violet-100 flex items-center justify-center text-violet-700">
                        <i className="fas fa-globe text-xl"></i>
                    </div>
                    <div className="flex-1">
                        <h3 className="font-semibold mb-1">Générateur de sites — bientôt disponible</h3>
                        <p className="text-sm text-gray-600 mb-3">
                            Chaque centrale dispose déjà d'un sous-domaine de réservation
                            <code className="mx-1 px-1.5 py-0.5 bg-gray-100 rounded text-xs">app.mypro.ch/CODECENTRALE/</code>
                            (cf. <strong>ch.mypro.app.central</strong>, PR2).
                        </p>
                        <p className="text-sm text-gray-600">
                            Le générateur de sites de présentation publics (équivalent SIMPLEBO dans l'ancien système)
                            sera intégré dans le PR3, avec templates configurables, hébergement Cloudflare Pages auto-provisionné
                            et page d'accueil personnalisée par centrale.
                        </p>
                        <div className="mt-4 flex gap-2 flex-wrap text-xs">
                            <span className="badge badge-violet">PR2 : app de réservation par centrale</span>
                            <span className="badge badge-muted">PR3 : générateur de sites publics</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
}

// ============================================================================
// ADMINS
// ============================================================================
function PageAdmins({ user }) {
    const { data, err, reload } = useResource(() => MyProAPI.admins(), []);
    const [editing, setEditing] = useState(null);
    const [confirm, setConfirm] = useState(null);

    async function save() {
        try {
            if (editing.id) await MyProAPI.updateAdmin(editing.id, { email: editing.email, name: editing.name, is_active: editing.is_active });
            else await MyProAPI.createAdmin(editing);
            toast('Enregistré'); setEditing(null); reload();
        } catch (e) { toast(e.message, 'error'); }
    }
    async function doDelete(id) {
        try { await MyProAPI.deleteAdmin(id); toast('Supprimé'); setConfirm(null); reload(); }
        catch (e) { toast(e.message, 'error'); }
    }

    return (
        <div>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Administrateurs</h1>
                    <div className="page-subtitle">Comptes ayant accès à cette interface.</div>
                </div>
                <button className="btn btn-primary" onClick={() => setEditing({ is_active: 1 })}>
                    <i className="fas fa-plus"></i> Nouvel admin
                </button>
            </div>
            {err && <div className="card text-red-600 mb-3">{err}</div>}
            {!data ? <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
             : (data.admins || []).length === 0 ? <div className="card text-center text-gray-500 py-10">Aucun admin</div>
             : (
                <div className="card" style={{ padding: 0, overflow: 'auto' }}>
                    <table className="data">
                        <thead><tr><th>Email</th><th>Nom</th><th>Statut</th><th></th></tr></thead>
                        <tbody>
                            {data.admins.map(a => (
                                <tr key={a.id}>
                                    <td className="font-mono text-sm">{a.email} {a.id === user.id && <span className="badge badge-violet ml-2">vous</span>}</td>
                                    <td>{a.name || '—'}</td>
                                    <td>{a.is_active ? <span className="badge badge-success">Actif</span> : <span className="badge badge-muted">Inactif</span>}</td>
                                    <td className="whitespace-nowrap">
                                        <button className="text-gray-500 hover:text-violet-600 px-2" onClick={() => setEditing(a)}><i className="fas fa-pen"></i></button>
                                        {a.id !== user.id && (
                                            <button className="text-gray-500 hover:text-red-600 px-2" onClick={() => setConfirm(a)}><i className="fas fa-trash"></i></button>
                                        )}
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            )}
            {editing && (
                <Modal title={editing.id ? 'Modifier l\'admin' : 'Nouvel admin'} onClose={() => setEditing(null)}
                    footer={<>
                        <button className="btn btn-secondary" onClick={() => setEditing(null)}>Annuler</button>
                        <button className="btn btn-primary" onClick={save}>Enregistrer</button>
                    </>}>
                    <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
                        <Field label="Email"><TextInput type="email" value={editing.email} onChange={v => setEditing(e => ({ ...e, email: v }))} required /></Field>
                        <Field label="Nom"><TextInput value={editing.name} onChange={v => setEditing(e => ({ ...e, name: v }))} /></Field>
                        <Field label="Actif"><Checkbox value={editing.is_active} onChange={v => setEditing(e => ({ ...e, is_active: v }))} label="Compte actif" /></Field>
                    </div>
                </Modal>
            )}
            {confirm && (
                <ConfirmDialog title="Supprimer l'admin" danger
                    message={`L'accès admin de ${confirm.email} sera révoqué.`}
                    confirmLabel="Supprimer"
                    onCancel={() => setConfirm(null)}
                    onConfirm={() => doDelete(confirm.id)} />
            )}
        </div>
    );
}

// ============================================================================
// Utilities
// ============================================================================
function stripMeta(obj) {
    const o = { ...obj };
    ['id', 'md5', 'created', 'modified', 'created_at', 'centrals_count', 'websites_count',
     'bookings_count_live', 'commissions_earned', 'total_commission_paid'].forEach(k => delete o[k]);
    return o;
}
function diffFields(orig, edited) {
    const diff = {};
    for (const k of Object.keys(edited)) {
        if (edited[k] !== orig[k]) diff[k] = edited[k];
    }
    ['id', 'md5', 'created', 'modified'].forEach(k => delete diff[k]);
    return diff;
}

// ============================================================================
// BOOKING DETAIL PAGE (admin)
// ============================================================================
function fmtMoney(v, currency = 'CHF') {
    if (v === null || v === undefined || v === '') return '—';
    const n = Number(v);
    return (Number.isFinite(n) ? n.toFixed(2) : v) + ' ' + currency;
}
function fmtDT(s) {
    if (!s) return '—';
    return String(s).replace('T', ' ').slice(0, 16);
}
function bookingStatusBadge(b) {
    if (b.cancelled)    return <span className="badge badge-danger">Annulée</span>;
    if (b.is_no_show)   return <span className="badge badge-warn">No-show</span>;
    if (b.is_completed) return <span className={`badge ${b.is_paid ? 'badge-success' : 'badge-warn'}`}>{b.is_paid ? 'Payée' : 'À payer'}</span>;
    if (b.selected_driver_id) return <span className="badge badge-info">Assignée</span>;
    return <span className="badge badge-muted">En attente</span>;
}

function BookingDetailPage({ id, onBack, onChanged }) {
    const { data, err, reload } = useResource(() => MyProAPI.booking(id), [id]);
    const [busy, setBusy] = useState(false);
    const [askCancel, setAskCancel] = useState(false);
    const [askRefund, setAskRefund] = useState(false);

    async function doAction(action, body) {
        setBusy(true);
        try {
            await MyProAPI.bookingAction(id, action, body || {});
            toast('Action effectuée');
            reload(); onChanged?.();
        } catch (e) { toast(e.message, 'error'); }
        finally { setBusy(false); setAskCancel(false); setAskRefund(false); }
    }

    if (err) return (
        <div>
            <button className="btn btn-secondary mb-3" onClick={onBack}><i className="fas fa-arrow-left"></i> Retour</button>
            <div className="card text-red-600">{err}</div>
        </div>
    );
    if (!data) return (
        <div>
            <button className="btn btn-secondary mb-3" onClick={onBack}><i className="fas fa-arrow-left"></i> Retour</button>
            <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
        </div>
    );

    const b = data.booking;
    const customer = ((b.customer_firstname || '') + ' ' + (b.customer_lastname || '')).trim() || 'Client';

    return (
        <div>
            <div className="flex items-center gap-2 text-sm text-gray-500 mb-3">
                <button className="hover:text-violet-600" onClick={onBack}>
                    <i className="fas fa-arrow-left mr-1"></i> Réservations
                </button>
                <i className="fas fa-chevron-right text-xs text-gray-300"></i>
                <span className="text-gray-900 font-medium">{b.reference || ('#' + b.id)}</span>
            </div>

            <div className="card flex items-center gap-4" style={{ padding: '14px 18px' }}>
                <div className="flex items-center justify-center text-white font-bold flex-shrink-0"
                     style={{ width: 52, height: 52, borderRadius: 12, background: '#6366f1', fontSize: 20 }}>
                    <i className="fas fa-route"></i>
                </div>
                <div className="min-w-0 flex-1">
                    <div className="flex items-center gap-2">
                        <span className="text-lg font-bold truncate">{b.reference || ('#' + b.id)}</span>
                        {bookingStatusBadge(b)}
                    </div>
                    <div className="text-xs text-gray-500 truncate">{b.central_label} · {customer} · {fmtDT(b.dated)}</div>
                </div>
                <div className="text-right flex-shrink-0">
                    <div className="text-2xl font-bold">{fmtMoney(b.price, b.currency)}</div>
                    <div className="text-xs text-gray-500">{b.payment_method || '—'} · {b.payment_status || '—'}</div>
                </div>
            </div>

            <div className="mt-4">
                <TabsView tabs={[
                    { id: 'details', label: 'Détails', icon: 'info-circle', render: () => (
                        <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                            <Section icon="hashtag" title="Référence & dates" iconColor="text-violet-600">
                                <Field label="Référence"><TextInput value={b.reference || ('#' + b.id)} disabled /></Field>
                                <Field label="Date course"><TextInput value={fmtDT(b.dated)} disabled /></Field>
                                <Field label="Créée le"><TextInput value={fmtDT(b.created)} disabled /></Field>
                                {b.no_show_at && <Field label="No-show à"><TextInput value={fmtDT(b.no_show_at)} disabled /></Field>}
                                {b.cancellation_reason && <Field label="Motif annulation"><TextInput value={b.cancellation_reason} disabled /></Field>}
                            </Section>

                            <Section icon="user" title="Client" iconColor="text-blue-600">
                                <Field label="Nom"><TextInput value={customer} disabled /></Field>
                                <Field label="Email"><TextInput value={b.customer_email || ''} disabled /></Field>
                                <Field label="Téléphone"><TextInput value={b.customer_mobile || ''} disabled /></Field>
                            </Section>

                            <Section icon="map-marker-alt" title="Trajet" iconColor="text-emerald-600" span="lg:col-span-2">
                                <Field label="Départ"><TextInput value={b.origin_address || ''} disabled /></Field>
                                <Field label="Arrivée"><TextInput value={b.destination_address || ''} disabled /></Field>
                                <div className="grid grid-cols-2 gap-3">
                                    <Field label="Distance (km)"><TextInput value={b.distance_km ?? '—'} disabled /></Field>
                                    <Field label="Durée (min)"><TextInput value={b.duration_min ?? '—'} disabled /></Field>
                                </div>
                            </Section>

                            <Section icon="user-tie" title="Chauffeur" iconColor="text-amber-600">
                                {data.driver ? (
                                    <>
                                        <Field label="Nom"><TextInput value={`${data.driver.firstname || ''} ${data.driver.lastname || ''}`.trim()} disabled /></Field>
                                        <Field label="Téléphone"><TextInput value={data.driver.mobile || ''} disabled /></Field>
                                        <Field label="Email"><TextInput value={data.driver.email || ''} disabled /></Field>
                                    </>
                                ) : (
                                    <div className="text-sm text-gray-500 italic">Aucun chauffeur assigné</div>
                                )}
                            </Section>

                            <Section icon="building" title="Centrale" iconColor="text-violet-600">
                                <Field label="Centrale"><TextInput value={b.central_label || ''} disabled /></Field>
                                <Field label="Site"><TextInput value={b.website_company || ''} disabled /></Field>
                            </Section>

                            <Section icon="credit-card" title="Paiement" iconColor="text-emerald-600" span="lg:col-span-2">
                                <div className="grid grid-cols-3 gap-3">
                                    <Field label="Prix"><TextInput value={fmtMoney(b.price, b.currency)} disabled /></Field>
                                    <Field label="Méthode"><TextInput value={b.payment_method || '—'} disabled /></Field>
                                    <Field label="Statut"><TextInput value={b.payment_status || '—'} disabled /></Field>
                                </div>
                                {data.payments && data.payments.length > 0 && (
                                    <div className="mt-3">
                                        <div className="text-xs text-gray-500 mb-1">Historique des paiements</div>
                                        <table className="data text-sm">
                                            <thead><tr><th>Date</th><th>Méthode</th><th>Statut</th><th>Montant</th><th>Note</th></tr></thead>
                                            <tbody>
                                                {data.payments.map(p => (
                                                    <tr key={p.id}>
                                                        <td className="text-xs">{fmtDT(p.created)}</td>
                                                        <td>{p.payment_method}</td>
                                                        <td>{p.status}</td>
                                                        <td className={p.amount < 0 ? 'text-red-600' : ''}>{fmtMoney(p.amount, p.currency || b.currency)}</td>
                                                        <td className="text-xs text-gray-500">{p.note || ''}</td>
                                                    </tr>
                                                ))}
                                            </tbody>
                                        </table>
                                    </div>
                                )}
                            </Section>

                            {data.proposals && data.proposals.length > 0 && (
                                <Section icon="paper-plane" title="Propositions chauffeurs" iconColor="text-cyan-600" span="lg:col-span-2">
                                    <table className="data text-sm">
                                        <thead><tr><th>Chauffeur</th><th>Notifié</th><th>Vu</th><th>Accepté</th><th>Refusé</th><th>Expire</th></tr></thead>
                                        <tbody>
                                            {data.proposals.map(p => (
                                                <tr key={p.id}>
                                                    <td>{p.firstname} {p.lastname} <span className="text-xs text-gray-400">#{p.driver_id}</span></td>
                                                    <td>{p.is_sms_notified || p.is_push_notified ? <i className="fas fa-check text-green-500"></i> : '—'}</td>
                                                    <td>{p.is_opened ? <i className="fas fa-check text-green-500"></i> : '—'}</td>
                                                    <td>{p.is_accepted ? <span className="badge badge-success">Oui</span> : '—'}</td>
                                                    <td>{p.is_declined ? <span className="badge badge-danger">Oui</span> : '—'}</td>
                                                    <td className="text-xs">{fmtDT(p.expired)}</td>
                                                </tr>
                                            ))}
                                        </tbody>
                                    </table>
                                </Section>
                            )}
                        </div>
                    )},

                    { id: 'danger', label: 'Zone danger', icon: 'exclamation-triangle', render: () => (
                        <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                            <Section icon="ban" title="Annuler la réservation" iconColor="text-red-600">
                                <p className="text-sm text-gray-600 mb-3">
                                    L'annulation est définitive. Le client recevra une notification.
                                </p>
                                <button className="btn btn-danger" disabled={busy || b.cancelled}
                                        onClick={() => setAskCancel(true)}>
                                    <i className="fas fa-ban"></i> {b.cancelled ? 'Déjà annulée' : 'Annuler la réservation'}
                                </button>
                            </Section>

                            <Section icon="rotate-left" title="Rembourser" iconColor="text-orange-600">
                                <p className="text-sm text-gray-600 mb-3">
                                    Crée une ligne de paiement négative et marque le paiement comme remboursé.
                                </p>
                                <button className="btn btn-danger" disabled={busy}
                                        onClick={() => setAskRefund(true)}>
                                    <i className="fas fa-undo"></i> Initier un remboursement
                                </button>
                            </Section>

                            <Section icon="user-slash" title="Marquer no-show" iconColor="text-amber-600">
                                <p className="text-sm text-gray-600 mb-3">
                                    Indique que le client ne s'est pas présenté.
                                </p>
                                <button className="btn btn-secondary" disabled={busy || b.is_no_show}
                                        onClick={() => doAction('no-show')}>
                                    <i className="fas fa-user-slash"></i> {b.is_no_show ? 'Déjà marquée no-show' : 'Marquer no-show'}
                                </button>
                            </Section>

                            <Section icon="circle-check" title="Marquer terminée" iconColor="text-emerald-600">
                                <p className="text-sm text-gray-600 mb-3">
                                    Force le statut "complétée" sans modifier le paiement.
                                </p>
                                <button className="btn btn-secondary" disabled={busy || b.is_completed}
                                        onClick={() => doAction('complete')}>
                                    <i className="fas fa-check"></i> {b.is_completed ? 'Déjà terminée' : 'Marquer terminée'}
                                </button>
                            </Section>
                        </div>
                    )},
                ]} />
            </div>

            {askCancel && <CancelBookingDialog onCancel={() => setAskCancel(false)}
                onConfirm={reason => doAction('cancel', { reason })} />}
            {askRefund && <RefundDialog defaultAmount={b.price} currency={b.currency}
                onCancel={() => setAskRefund(false)}
                onConfirm={(amount, reason) => doAction('refund', { amount, reason, currency: b.currency })} />}
        </div>
    );
}

function CancelBookingDialog({ onCancel, onConfirm }) {
    const [reason, setReason] = useState('');
    return (
        <Modal title="Annuler la réservation" onClose={onCancel} footer={
            <>
                <button className="btn btn-secondary" onClick={onCancel}>Retour</button>
                <button className="btn btn-danger" onClick={() => onConfirm(reason)}>
                    <i className="fas fa-ban"></i> Annuler définitivement
                </button>
            </>
        }>
            <p className="text-sm text-gray-700 mb-3">Indiquez le motif (optionnel) :</p>
            <TextArea value={reason} onChange={setReason} rows={3} />
        </Modal>
    );
}

function RefundDialog({ defaultAmount, currency, onCancel, onConfirm }) {
    const [amount, setAmount] = useState(defaultAmount || '');
    const [reason, setReason] = useState('');
    return (
        <Modal title="Initier un remboursement" onClose={onCancel} footer={
            <>
                <button className="btn btn-secondary" onClick={onCancel}>Retour</button>
                <button className="btn btn-danger" disabled={!(parseFloat(amount) > 0)}
                        onClick={() => onConfirm(parseFloat(amount), reason)}>
                    <i className="fas fa-undo"></i> Rembourser
                </button>
            </>
        }>
            <Field label={`Montant (${currency || 'CHF'})`}>
                <TextInput type="number" value={amount} onChange={setAmount} />
            </Field>
            <Field label="Motif (optionnel)">
                <TextArea value={reason} onChange={setReason} rows={3} />
            </Field>
        </Modal>
    );
}

// ============================================================================
// DRIVER DETAIL PAGE (admin)
// ============================================================================
function DriverDetailPage({ id, onBack, onChanged }) {
    const { data, err, reload } = useResource(() => MyProAPI.driver(id), [id]);
    const [bookings, setBookings] = useState(null);
    const [d, setD] = useState(null);
    const [saving, setSaving] = useState(false);
    const [selectedBooking, setSelectedBooking] = useState(null);

    useEffect(() => { if (data) setD({ ...data.driver }); }, [data]);
    useEffect(() => { MyProAPI.driverBookings(id).then(r => setBookings(r.bookings || [])).catch(() => setBookings([])); }, [id]);

    if (selectedBooking) {
        return <BookingDetailPage id={selectedBooking}
            onBack={() => setSelectedBooking(null)} onChanged={() => {}} />;
    }

    if (err) return (
        <div>
            <button className="btn btn-secondary mb-3" onClick={onBack}><i className="fas fa-arrow-left"></i> Retour</button>
            <div className="card text-red-600">{err}</div>
        </div>
    );
    if (!data || !d) return (
        <div>
            <button className="btn btn-secondary mb-3" onClick={onBack}><i className="fas fa-arrow-left"></i> Retour</button>
            <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
        </div>
    );

    const set = (k, v) => setD(s => ({ ...s, [k]: v }));
    const dirty = Object.keys(diffFields(data.driver, d)).length > 0;

    async function save() {
        setSaving(true);
        try {
            await MyProAPI.updateDriver(id, diffFields(data.driver, d));
            toast('Enregistré');
            reload(); onChanged?.();
        } catch (e) { toast(e.message, 'error'); }
        finally { setSaving(false); }
    }

    const initials = (((d.firstname || '?').charAt(0)) + ((d.lastname || '').charAt(0))).toUpperCase();
    const stats = data.stats || {};

    return (
        <div>
            <div className="flex items-center gap-2 text-sm text-gray-500 mb-3">
                <button className="hover:text-violet-600" onClick={onBack}>
                    <i className="fas fa-arrow-left mr-1"></i> Chauffeurs
                </button>
                <i className="fas fa-chevron-right text-xs text-gray-300"></i>
                <span className="text-gray-900 font-medium">{d.firstname} {d.lastname}</span>
            </div>

            <div className="card flex items-center gap-4" style={{ padding: '14px 18px' }}>
                <div className="flex items-center justify-center text-white font-bold flex-shrink-0"
                     style={{ width: 52, height: 52, borderRadius: 12, background: '#0ea5e9', fontSize: 20 }}>
                    {initials}
                </div>
                <div className="min-w-0 flex-1">
                    <div className="flex items-center gap-2">
                        <span className="text-lg font-bold truncate">{d.firstname} {d.lastname}</span>
                        {d.is_star ? <span className="badge badge-warn"><i className="fas fa-star"></i></span> : null}
                        {d.is_online ? <span className="badge badge-success">● online</span> : <span className="badge badge-muted">○ offline</span>}
                        {!d.is_active && <span className="badge badge-danger">Désactivé</span>}
                    </div>
                    <div className="text-xs text-gray-500 truncate">{data.driver.central_label || '—'} · {d.email} · {d.mobile}</div>
                </div>
                <div className="flex items-center gap-2 flex-shrink-0">
                    <button className="btn btn-primary" onClick={save} disabled={saving || !dirty}>
                        {saving ? <span className="spinner-dot"></span> : (dirty ? 'Enregistrer' : 'À jour')}
                    </button>
                </div>
            </div>

            <div className="grid grid-cols-2 md:grid-cols-4 gap-3 mt-4">
                <StatBlock icon="route"        color="#6366f1" label="Courses totales" value={stats.total ?? 0} />
                <StatBlock icon="circle-check" color="#10b981" label="Terminées"        value={stats.completed ?? 0} />
                <StatBlock icon="ban"          color="#ef4444" label="Annulées"         value={stats.cancelled ?? 0} />
                <StatBlock icon="coins"        color="#f59e0b" label="CA généré"        value={fmtMoney(stats.revenue ?? 0)} />
            </div>

            <div className="mt-4">
                <TabsView tabs={[
                    { id: 'coords', label: 'Coordonnées', icon: 'address-card', render: () => (
                        <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                            <Section icon="user" title="Identité" iconColor="text-violet-600">
                                <div className="grid grid-cols-2 gap-3">
                                    <Field label="Prénom"><TextInput value={d.firstname} onChange={v => set('firstname', v)} /></Field>
                                    <Field label="Nom"><TextInput value={d.lastname} onChange={v => set('lastname', v)} /></Field>
                                </div>
                                <Field label="Date de naissance"><DatePicker value={d.birthday || ''} onChange={v => set('birthday', v)} minDate={null} placeholder="JJ/MM/AAAA" /></Field>
                                <Field label="Adresse"><TextInput value={d.address} onChange={v => set('address', v)} /></Field>
                            </Section>

                            <Section icon="envelope" title="Contact" iconColor="text-blue-600">
                                <Field label="Email"><TextInput type="email" value={d.email} onChange={v => set('email', v)} /></Field>
                                <Field label="Téléphone mobile"><TextInput value={d.mobile} onChange={v => set('mobile', v)} /></Field>
                            </Section>

                            <Section icon="building" title="Affectation" iconColor="text-amber-600" span="lg:col-span-2">
                                <Field label="Centrale ID"><TextInput type="number" value={d.central_id} onChange={v => set('central_id', parseInt(v))} /></Field>
                                <Field label="Centrale"><TextInput value={data.driver.central_label || ''} disabled /></Field>
                            </Section>
                        </div>
                    )},

                    { id: 'bookings', label: 'Courses', icon: 'route', render: () => (
                        <div className="card" style={{ padding: 0 }}>
                            {bookings === null ? <div className="flex justify-center py-10"><div className="loading-spinner"></div></div>
                             : bookings.length === 0 ? <div className="text-center text-gray-500 py-10">Aucune course</div>
                             : (
                                <table className="data">
                                    <thead><tr><th>Réf</th><th>Date</th><th>Client</th><th>Trajet</th><th>Prix</th><th>Statut</th></tr></thead>
                                    <tbody>
                                        {bookings.map(b => (
                                            <tr key={b.id} className="row-link" onClick={() => setSelectedBooking(b.id)}>
                                                <td><strong>{b.reference || ('#' + b.id)}</strong></td>
                                                <td className="text-xs whitespace-nowrap">{fmtDT(b.dated)}</td>
                                                <td className="text-sm">{((b.customer_firstname || '') + ' ' + (b.customer_lastname || '')).trim()}</td>
                                                <td className="text-xs max-w-xs">
                                                    <div className="truncate">↑ {b.origin_address}</div>
                                                    <div className="truncate">↓ {b.destination_address}</div>
                                                </td>
                                                <td className="whitespace-nowrap">{fmtMoney(b.price)}</td>
                                                <td>{bookingStatusBadge(b)}</td>
                                            </tr>
                                        ))}
                                    </tbody>
                                </table>
                             )}
                        </div>
                    )},

                    { id: 'options', label: 'Options', icon: 'sliders', render: () => (
                        <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                            <Section icon="power-off" title="Statut" iconColor="text-emerald-600">
                                <ToggleRow icon="check-circle" iconColor="text-emerald-600" title="Compte actif"
                                    desc="Désactiver bloque la réception des courses"
                                    value={!!d.is_active} onChange={v => set('is_active', v ? 1 : 0)} />
                                <ToggleRow icon="circle-dot" iconColor="text-blue-500" title="Disponible"
                                    desc="Chauffeur prêt à prendre des courses"
                                    value={!!d.is_available} onChange={v => set('is_available', v ? 1 : 0)} />
                                <ToggleRow icon="bolt" iconColor="text-violet-600" title="Dispatch automatique"
                                    desc="Inclus dans les pools auto"
                                    value={!!d.is_automatic} onChange={v => set('is_automatic', v ? 1 : 0)} />
                            </Section>

                            <Section icon="star" title="Réputation" iconColor="text-amber-500">
                                <ToggleRow icon="star" iconColor="text-amber-500" title="Chauffeur star"
                                    desc="Mis en avant dans le dispatch prioritaire"
                                    value={!!d.is_star} onChange={v => set('is_star', v ? 1 : 0)} />
                                <ToggleRow icon="eye" iconColor="text-cyan-600" title="Repéré"
                                    desc="Surveillance / observation interne"
                                    value={!!d.is_spotted} onChange={v => set('is_spotted', v ? 1 : 0)} />
                            </Section>

                            <Section icon="comment" title="Note interne" iconColor="text-gray-600" span="lg:col-span-2">
                                <Field label="Commentaire">
                                    <TextArea value={d.comment} onChange={v => set('comment', v)} rows={4} />
                                </Field>
                            </Section>
                        </div>
                    )},
                ]} />
            </div>
        </div>
    );
}

function StatBlock({ icon, color, label, value }) {
    return (
        <div className="card">
            <div className="flex items-center gap-3 mb-1">
                <div className="w-9 h-9 rounded-lg flex items-center justify-center"
                     style={{ background: color + '18', color }}>
                    <i className={`fas fa-${icon}`}></i>
                </div>
                <div className="text-xs text-gray-500">{label}</div>
            </div>
            <div className="text-xl font-bold">{value}</div>
        </div>
    );
}

// ============================================================================
// ROOT
// ============================================================================
function App() {
    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        (async () => {
            if (MyProAuth.isAuthenticated()) {
                const u = await MyProAuth.refreshUser().catch(() => null);
                if (u && u.type === 'admin') setUser(u);
                else MyProAuth.clearAuth();
            }
            setLoading(false);
        })();
    }, []);

    if (loading) return <div className="flex items-center justify-center min-h-screen"><div className="loading-spinner"></div></div>;
    return user ? <Dashboard user={user} /> : <Login />;
}

function Dashboard({ user }) {
    const [page, setPage] = useState('dashboard');
    let body;
    if      (page === 'dashboard')   body = <PageDashboard user={user} />;
    else if (page === 'diffusion')   body = <PageDiffusion />;
    else if (page === 'accounts')    body = <PageAccounts />;
    else if (page === 'operators')   body = <PageOperators />;
    else if (page === 'bookings')    body = <PageBookings />;
    else if (page === 'drivers')     body = <PageDrivers />;
    else if (page === 'partners')    body = <PagePartners />;
    else if (page === 'commissions') body = <PageCommissions />;
    else if (page === 'sms')         body = <PageSms />;
    else if (page === 'sites')       body = <PageSites />;
    else if (page === 'admins')      body = <PageAdmins user={user} />;
    else body = <div className="card text-gray-500">Page inconnue : {page}</div>;
    return <Layout user={user} page={page} setPage={setPage}>{body}</Layout>;
}

const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(<App />);
