// ============================================================================
// Swissapp Space - PWA mobile (React 18 + Tailwind via CDN, Babel runtime)
// ============================================================================

const { useState, useEffect, useRef, useCallback, useMemo, createContext, useContext } = React;

// =================== CONFIG ===================
const CONFIG = {
    API_URL: 'https://api.swissapp.org',
    SSO_URL: 'https://api.sso.swissapp.net',
    REDIRECT_URI: window.location.origin,
    STORAGE_TOKEN: 'swissapp_token',
    STORAGE_USER: 'swissapp_user'
};

const SERVICES = [
    { id: 'sms',    label: 'SMS',     icon: 'fa-comment-sms',     color: '#dc2626', endpoint: 'api.sms.swissapp.net' },
    { id: 'mails',  label: 'Emails',  icon: 'fa-envelope',        color: '#2563eb', endpoint: 'api.mails.swissapp.net' },
    { id: 'files',  label: 'Fichiers',icon: 'fa-folder-tree',     color: '#059669', endpoint: 'api.files.swissapp.net' },
    { id: 'agents', label: 'Agents IA',icon: 'fa-robot',          color: '#7c3aed', endpoint: 'api.agents.swissapp.net' },
    { id: 'maps',   label: 'Maps',    icon: 'fa-map-location-dot',color: '#ea580c', endpoint: 'api.maps.swissapp.net' }
];

const COUNTRY_FLAGS = { CH: '🇨🇭', FR: '🇫🇷', DE: '🇩🇪', IT: '🇮🇹', ES: '🇪🇸', BE: '🇧🇪', LU: '🇱🇺', GB: '🇬🇧', US: '🇺🇸', CA: '🇨🇦', AT: '🇦🇹', NL: '🇳🇱', PT: '🇵🇹' };
const SMS_STATUS_BADGES = {
    sent: { label: 'Envoyé', className: 'sw-badge-success' },
    pending: { label: 'En attente', className: 'sw-badge-warn' },
    standby: { label: 'File', className: 'sw-badge-info' },
    failed: { label: 'Échec', className: 'sw-badge-danger' },
    cancelled: { label: 'Annulé', className: 'sw-badge-neutral' }
};

// =================== HELPERS ===================
function getToken() { return localStorage.getItem(CONFIG.STORAGE_TOKEN); }
function setToken(t) { localStorage.setItem(CONFIG.STORAGE_TOKEN, t); }
function clearAuth() { localStorage.removeItem(CONFIG.STORAGE_TOKEN); localStorage.removeItem(CONFIG.STORAGE_USER); }

async function apiFetch(path, options = {}) {
    const token = getToken();
    const headers = { 'Content-Type': 'application/json', ...(options.headers || {}) };
    if (token) headers.Authorization = `Bearer ${token}`;
    const res = await fetch(`${CONFIG.API_URL}${path}`, { ...options, headers });
    let data = null;
    try { data = await res.json(); } catch { /* ignore */ }
    if (res.status === 401) {
        clearAuth();
        window.location.reload();
        return null;
    }
    return data;
}

function fmtCHF(cents) {
    const v = (cents / 100);
    return v % 1 === 0 ? `${v} CHF` : `${v.toFixed(2)} CHF`;
}
function fmtDate(d, opts) {
    if (!d) return '—';
    return new Date(d).toLocaleString('fr-CH', opts || { day: '2-digit', month: '2-digit', year: 'numeric' });
}
function fmtDateTime(d) {
    if (!d) return '—';
    return new Date(d).toLocaleString('fr-CH', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
}

// =================== APP CONTEXT ===================
const AppContext = createContext(null);
const useApp = () => useContext(AppContext);

const AppProvider = ({ children }) => {
    const [user, setUser] = useState(() => {
        try { return JSON.parse(localStorage.getItem(CONFIG.STORAGE_USER)); } catch { return null; }
    });
    const [authed, setAuthed] = useState(false);
    const [bootLoading, setBootLoading] = useState(true);
    const [view, setView] = useState('home');
    const [serviceView, setServiceView] = useState(null); // 'sms', 'mails', etc.
    const [toasts, setToasts] = useState([]);
    const [modal, setModal] = useState(null);

    // ---- Toast API ----
    const showToast = useCallback((message, type = 'info', duration = 3500) => {
        const id = Date.now() + Math.random();
        setToasts(t => [...t, { id, message, type }]);
        setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), duration);
    }, []);

    // ---- Modal API ----
    const openModal = useCallback((node) => setModal(node), []);
    const closeModal = useCallback(() => setModal(null), []);

    // ---- Bootstrap auth ----
    useEffect(() => {
        let cancelled = false;
        async function boot() {
            // 1. Magic link callback
            const params = new URLSearchParams(window.location.search);
            const magicToken = params.get('magic_token');
            const callbackToken = params.get('token');
            const rechargeStatus = params.get('recharge');

            if (magicToken) {
                try {
                    const r = await fetch(`${CONFIG.SSO_URL}/auth/magic-link/verify`, {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ token: magicToken })
                    });
                    const d = await r.json();
                    if (d.success && d.token) setToken(d.token);
                } catch (e) { console.error(e); }
                window.history.replaceState({}, '', window.location.pathname);
            } else if (callbackToken) {
                setToken(callbackToken);
                window.history.replaceState({}, '', window.location.pathname);
            }

            // 2. Verify token
            const tok = getToken();
            if (tok) {
                try {
                    const r = await fetch(`${CONFIG.API_URL}/api/me`, { headers: { Authorization: `Bearer ${tok}` } });
                    const d = await r.json();
                    if (!cancelled && d.success && d.user) {
                        setUser(d.user);
                        localStorage.setItem(CONFIG.STORAGE_USER, JSON.stringify(d.user));
                        setAuthed(true);
                    } else { clearAuth(); }
                } catch { clearAuth(); }
            }

            // 3. Recharge return
            if (rechargeStatus === 'success') {
                showToast('Paiement reçu ! Vos crédits arrivent…', 'success');
                window.history.replaceState({}, '', window.location.pathname);
            } else if (rechargeStatus === 'cancel') {
                showToast('Paiement annulé', 'info');
                window.history.replaceState({}, '', window.location.pathname);
            }

            if (!cancelled) setBootLoading(false);
        }
        boot();
        return () => { cancelled = true; };
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    const logout = useCallback(() => {
        clearAuth();
        setUser(null);
        setAuthed(false);
        window.location.reload();
    }, []);

    return (
        <AppContext.Provider value={{
            user, setUser, authed, setAuthed, bootLoading,
            view, setView, serviceView, setServiceView,
            showToast, modal, openModal, closeModal, logout
        }}>
            {children}
            <ToastStack toasts={toasts} />
            {modal && <ModalHost>{modal}</ModalHost>}
        </AppContext.Provider>
    );
};

// =================== TOAST ===================
const ToastStack = ({ toasts }) => (
    <div className="fixed top-0 left-0 right-0 z-[1100] pointer-events-none">
        {toasts.map(t => (
            <div key={t.id} className={`toast ${t.type}`}>
                <i className={`fas ${t.type === 'success' ? 'fa-circle-check' : t.type === 'error' ? 'fa-circle-exclamation' : 'fa-circle-info'}`} />
                <span>{t.message}</span>
            </div>
        ))}
    </div>
);

// =================== MODAL ===================
const ModalHost = ({ children }) => {
    const { closeModal } = useApp();
    return (
        <div className="modal-overlay" onClick={(e) => { if (e.target === e.currentTarget) closeModal(); }}>
            <div className="modal-content sw-scroll">{children}</div>
        </div>
    );
};

const ModalHeader = ({ title, subtitle, onClose }) => {
    const { closeModal } = useApp();
    return (
        <div className="px-6 pt-6 pb-4 border-b border-sw-border flex items-start justify-between gap-3 sticky top-0 bg-white z-10">
            <div>
                <h3 className="text-lg font-bold text-slate-900">{title}</h3>
                {subtitle && <p className="text-sm text-slate-500 mt-0.5">{subtitle}</p>}
            </div>
            <button onClick={onClose || closeModal} className="text-slate-400 hover:text-slate-700 transition-colors p-1 -mr-1">
                <i className="fas fa-times text-lg" />
            </button>
        </div>
    );
};

// =================== LOGIN ===================
const LoginScreen = () => {
    const { showToast } = useApp();
    const [email, setEmail] = useState('');
    const [sending, setSending] = useState(false);
    const [sent, setSent] = useState(false);

    const sendMagicLink = async (e) => {
        e.preventDefault();
        if (!email || sending) return;
        setSending(true);
        try {
            const r = await fetch(`${CONFIG.SSO_URL}/auth/magic-link`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ email, redirect_uri: CONFIG.REDIRECT_URI })
            });
            const d = await r.json();
            if (d.success) setSent(true);
            else showToast(d.error || 'Erreur', 'error');
        } catch {
            showToast('Erreur réseau', 'error');
        } finally { setSending(false); }
    };

    const loginGoogle = () => {
        window.location.href = `${CONFIG.SSO_URL}/auth/google?redirect_uri=${encodeURIComponent(CONFIG.REDIRECT_URI)}`;
    };

    return (
        <div className="h-full w-full flex items-center justify-center px-5 py-8" style={{ background: 'linear-gradient(180deg, #fee2e2 0%, #f1f5f9 100%)' }}>
            <div className="w-full max-w-sm sw-card p-6 fade-in-up">
                <div className="flex flex-col items-center mb-6">
                    <div className="w-16 h-16 rounded-2xl flex items-center justify-center text-white text-2xl font-extrabold mb-4 shadow-lg" style={{ background: 'linear-gradient(135deg, #e63946, #7f1d1d)' }}>S</div>
                    <h1 className="text-xl font-extrabold text-slate-900">Swissapp Space</h1>
                    <p className="text-sm text-slate-500 mt-1 text-center">Gérez vos services en un seul endroit</p>
                </div>

                {!sent ? (
                    <>
                        <button onClick={loginGoogle}
                            className="w-full flex items-center justify-center gap-3 py-3.5 px-4 border border-sw-border rounded-2xl font-semibold text-slate-800 hover:bg-slate-50 transition-colors mb-4">
                            <img src="https://www.google.com/favicon.ico" alt="" className="w-5 h-5" />
                            Continuer avec Google
                        </button>
                        <div className="flex items-center gap-3 my-4 text-xs text-slate-400 font-semibold">
                            <div className="flex-1 border-t border-sw-border" />
                            ou
                            <div className="flex-1 border-t border-sw-border" />
                        </div>
                        <form onSubmit={sendMagicLink} className="space-y-3">
                            <input type="email" required value={email} onChange={e => setEmail(e.target.value)}
                                placeholder="Adresse email" className="sw-input" />
                            <button type="submit" disabled={sending} className="sw-btn sw-btn-primary w-full">
                                {sending ? <><i className="fas fa-spinner fa-spin" /> Envoi…</> : <><i className="fas fa-paper-plane" /> Recevoir un lien</>}
                            </button>
                        </form>
                    </>
                ) : (
                    <div className="text-center py-6">
                        <div className="w-14 h-14 rounded-full bg-emerald-100 mx-auto flex items-center justify-center mb-3">
                            <i className="fas fa-check text-2xl text-emerald-600" />
                        </div>
                        <p className="font-bold text-slate-900 mb-1">Email envoyé !</p>
                        <p className="text-sm text-slate-500">Cliquez sur le lien reçu pour vous connecter.</p>
                    </div>
                )}

                <p className="text-xs text-center text-slate-400 mt-6">
                    En continuant, vous acceptez les <a href="https://swissapp.org" className="text-sw-red font-semibold">CGU</a>.
                </p>
            </div>
        </div>
    );
};

// =================== HEADER ===================
const Header = ({ title, subtitle, back, action }) => {
    const { setView, setServiceView } = useApp();
    return (
        <header className="app-header">
            <div className="flex items-center justify-between gap-3">
                {back ? (
                    <button onClick={back} className="w-9 h-9 flex items-center justify-center rounded-xl bg-white/15 hover:bg-white/25 transition-colors">
                        <i className="fas fa-chevron-left" />
                    </button>
                ) : (
                    <div className="flex items-center gap-2.5">
                        <div className="w-9 h-9 rounded-xl bg-white/15 backdrop-blur flex items-center justify-center font-extrabold">S</div>
                        <div>
                            <div className="font-bold leading-tight text-[0.95rem]">Swissapp</div>
                            <div className="text-[0.65rem] text-white/70 leading-tight">Space</div>
                        </div>
                    </div>
                )}

                <div className={`flex-1 ${back ? '' : 'text-right'}`}>
                    {title && <div className="font-bold text-base leading-tight">{title}</div>}
                    {subtitle && <div className="text-xs text-white/70 leading-tight">{subtitle}</div>}
                </div>

                {action || <div className="w-9 h-9" />}
            </div>
        </header>
    );
};

// =================== SKELETONS ===================
const SkeletonRows = ({ count = 4, height = 'h-14' }) => (
    <div className="space-y-2">
        {Array.from({ length: count }).map((_, i) => (
            <div key={i} className={`skeleton ${height} rounded-xl`} />
        ))}
    </div>
);

// =================== HOME / DASHBOARD ===================
const HomeView = () => {
    const { user, setView, setServiceView } = useApp();
    const [stats, setStats] = useState(null);
    const [credits, setCredits] = useState({ sms: null, agents: null });

    useEffect(() => {
        (async () => {
            try {
                const [u, sms, ag] = await Promise.all([
                    apiFetch('/api/usage'),
                    apiFetch('/api/sms/credits'),
                    apiFetch('/api/agents/credits')
                ]);
                if (u?.success) setStats(u.usage || u);
                setCredits({ sms: sms?.success ? sms : null, agents: ag?.success ? ag : null });
            } catch {}
        })();
    }, []);

    return (
        <div className="h-full overflow-auto sw-scroll pb-6">
            <Header
                title="Bonjour"
                subtitle={user?.name || user?.email}
                action={
                    <button onClick={() => setView('account')}
                        className="w-9 h-9 rounded-full bg-white/20 flex items-center justify-center text-sm font-bold">
                        {(user?.name || user?.email || '?')[0].toUpperCase()}
                    </button>
                }
            />

            <div className="px-4 pt-4 space-y-4">
                {/* Welcome card */}
                <div className="sw-card p-5 fade-in-up">
                    <h2 className="font-extrabold text-lg text-slate-900">Tableau de bord</h2>
                    <p className="text-sm text-slate-500">Vos services en un coup d'œil</p>
                </div>

                {/* Credits */}
                <div className="grid grid-cols-2 gap-3 fade-in-up">
                    <CreditMiniCard service="sms" data={credits.sms} />
                    <CreditMiniCard service="agents" data={credits.agents} />
                </div>

                {/* Services */}
                <div className="fade-in-up">
                    <div className="text-xs font-bold uppercase tracking-wider text-slate-400 px-1 mb-2">Mes services</div>
                    <div className="grid grid-cols-2 gap-3">
                        {SERVICES.map(s => (
                            <button key={s.id} className="sw-tile stagger-item"
                                onClick={() => { setServiceView(s.id); setView('services'); }}>
                                <i className={`fas ${s.icon} sw-tile-icon`} />
                                <div className="sw-tile-label">{s.label}</div>
                                <div className="sw-tile-hint">{s.endpoint}</div>
                            </button>
                        ))}
                        <button className="sw-tile stagger-item" onClick={() => setView('modules')}>
                            <i className="fas fa-puzzle-piece sw-tile-icon" />
                            <div className="sw-tile-label">Modules</div>
                            <div className="sw-tile-hint">Booking, Rental…</div>
                        </button>
                    </div>
                </div>

                {/* Quick actions */}
                <div className="fade-in-up">
                    <div className="text-xs font-bold uppercase tracking-wider text-slate-400 px-1 mb-2">Actions rapides</div>
                    <div className="space-y-2">
                        <QuickAction icon="fa-bolt" label="Recharger SMS" hint="Achat de pack via Stripe"
                            onClick={() => { setServiceView('sms'); setView('services'); setTimeout(() => window.dispatchEvent(new CustomEvent('open-recharge', { detail: 'sms' })), 100); }} />
                        <QuickAction icon="fa-key" label="Mes clés API" hint="Gérer toutes les clés"
                            onClick={() => setView('account')} />
                        <QuickAction icon="fa-receipt" label="Mes factures" hint="Historique des paiements"
                            onClick={() => setView('billing')} />
                    </div>
                </div>
            </div>
        </div>
    );
};

const CreditMiniCard = ({ service, data }) => {
    const isLoading = data === null;
    const balance = data?.balance ?? 0;
    const lastPack = data?.last_pack_units ?? 0;
    const pct = lastPack > 0 ? Math.min(100, Math.round((balance / lastPack) * 100)) : 0;
    const level = data?.level || 'ok';
    const colorMap = { ok: '#16a34a', low: '#ca8a04', very_low: '#ea580c', empty: '#dc2626' };
    const color = colorMap[level];
    const icon = service === 'sms' ? 'fa-comment-sms' : 'fa-robot';
    const label = service === 'sms' ? 'SMS' : 'Requêtes IA';

    return (
        <div className="sw-card p-4">
            <div className="flex items-center justify-between mb-2">
                <span className="text-xs font-semibold text-slate-500">{label}</span>
                <i className={`fas ${icon} text-base`} style={{ color }} />
            </div>
            {isLoading ? (
                <div className="skeleton h-7 w-16 mb-1" />
            ) : (
                <div className="text-2xl font-extrabold" style={{ color: '#0f172a' }}>{balance}</div>
            )}
            <div className="mt-1 h-1.5 bg-slate-100 rounded-full overflow-hidden">
                <div className="h-full transition-all" style={{ width: `${pct}%`, backgroundColor: color }} />
            </div>
        </div>
    );
};

const QuickAction = ({ icon, label, hint, onClick }) => (
    <button onClick={onClick} className="sw-card w-full p-3 flex items-center gap-3 text-left hover:bg-slate-50 transition-colors">
        <div className="w-10 h-10 rounded-xl bg-sw-red-soft flex items-center justify-center text-sw-red flex-shrink-0">
            <i className={`fas ${icon}`} />
        </div>
        <div className="flex-1 min-w-0">
            <div className="font-semibold text-slate-900 text-sm">{label}</div>
            <div className="text-xs text-slate-500">{hint}</div>
        </div>
        <i className="fas fa-chevron-right text-slate-300 text-xs" />
    </button>
);

// =================== SERVICES VIEW ===================
const ServicesView = () => {
    const { serviceView, setServiceView, setView } = useApp();

    if (serviceView) {
        return <ServiceDetail serviceId={serviceView} onBack={() => setServiceView(null)} />;
    }

    return (
        <div className="h-full overflow-auto sw-scroll pb-6">
            <Header title="Services" subtitle="Choisissez un service" />
            <div className="px-4 pt-4">
                <div className="grid grid-cols-2 gap-3">
                    {SERVICES.map(s => (
                        <button key={s.id} className="sw-tile stagger-item" onClick={() => setServiceView(s.id)}>
                            <i className={`fas ${s.icon} sw-tile-icon`} style={{ background: `linear-gradient(135deg, ${s.color}, ${s.color}88)`, WebkitBackgroundClip: 'text' }} />
                            <div className="sw-tile-label">{s.label}</div>
                            <div className="sw-tile-hint">{s.endpoint}</div>
                        </button>
                    ))}
                </div>
            </div>
        </div>
    );
};

// =================== SERVICE DETAIL ===================
const ServiceDetail = ({ serviceId, onBack }) => {
    const service = SERVICES.find(s => s.id === serviceId);
    const { showToast, openModal, closeModal } = useApp();
    const [keys, setKeys] = useState(null);
    const [selectedKey, setSelectedKey] = useState(() => localStorage.getItem(`sw_key_${serviceId}`));
    const [credits, setCredits] = useState(null);
    const [history, setHistory] = useState(null);

    const loadKeys = useCallback(async () => {
        const d = await apiFetch('/api/keys');
        if (d?.success) {
            const filtered = (d.keys || []).filter(k => k.service === serviceId);
            setKeys(filtered);
            if (!selectedKey && filtered[0]) {
                setSelectedKey(filtered[0].id);
                localStorage.setItem(`sw_key_${serviceId}`, filtered[0].id);
            }
        } else { setKeys([]); }
    }, [serviceId, selectedKey]);

    useEffect(() => {
        loadKeys();
        if (serviceId === 'sms' || serviceId === 'agents') {
            apiFetch(`/api/${serviceId}/credits`).then(d => d?.success && setCredits(d));
            if (serviceId === 'sms') apiFetch('/api/sms/history?limit=20').then(d => setHistory(d?.history || []));
            else apiFetch('/api/agents/history').then(d => setHistory(d?.history || []));
        }
    }, [serviceId, loadKeys]);

    // Listen for "open-recharge" event from quick actions
    useEffect(() => {
        const handler = (e) => {
            if (e.detail === serviceId) openRecharge();
        };
        window.addEventListener('open-recharge', handler);
        return () => window.removeEventListener('open-recharge', handler);
        // eslint-disable-next-line
    }, [serviceId]);

    const openRecharge = () => {
        if (serviceId !== 'sms' && serviceId !== 'agents') return;
        openModal(<RechargeModal service={serviceId} onClose={closeModal} />);
    };

    const openCreateKey = () => {
        openModal(<CreateKeyModal forcedService={serviceId} onClose={closeModal} onCreated={() => { closeModal(); loadKeys(); }} />);
    };

    const deleteKey = async (id) => {
        if (!confirm('Supprimer cette clé API ?')) return;
        const d = await apiFetch(`/api/keys/${id}`, { method: 'DELETE' });
        if (d?.success) { showToast('Clé supprimée', 'success'); loadKeys(); }
        else showToast(d?.error || 'Erreur', 'error');
    };

    return (
        <div className="h-full overflow-auto sw-scroll pb-6">
            <Header
                title={service.label}
                subtitle={service.endpoint}
                back={onBack}
                action={
                    (serviceId === 'sms' || serviceId === 'agents') && (
                        <button onClick={openRecharge} className="px-3 h-9 rounded-xl bg-white/15 hover:bg-white/25 transition-colors text-sm font-bold flex items-center gap-1.5">
                            <i className="fas fa-bolt" /> Recharger
                        </button>
                    )
                }
            />

            <div className="px-4 pt-4 space-y-4">
                {/* Credits card (SMS / Agents) */}
                {(serviceId === 'sms' || serviceId === 'agents') && (
                    <CreditPanel service={serviceId} data={credits} onRecharge={openRecharge} />
                )}

                {/* Maps usage */}
                {serviceId === 'maps' && <MapsUsagePanel />}

                {/* Keys */}
                <div className="sw-card overflow-hidden">
                    <div className="px-4 py-3 border-b border-sw-border flex items-center justify-between">
                        <div>
                            <div className="font-bold text-slate-900">Clés API</div>
                            <div className="text-xs text-slate-500">Pour appeler {service.endpoint}</div>
                        </div>
                        <button onClick={openCreateKey} className="sw-btn sw-btn-primary !py-2 !px-3 text-xs">
                            <i className="fas fa-plus" /> Nouvelle
                        </button>
                    </div>
                    <div className="p-3">
                        {keys === null ? <SkeletonRows count={3} /> : keys.length === 0 ? (
                            <div className="text-center py-8 text-sm text-slate-400">
                                Aucune clé pour ce service
                                <button onClick={openCreateKey} className="sw-btn sw-btn-primary mt-3 mx-auto !text-xs">
                                    <i className="fas fa-plus" /> Créer une clé
                                </button>
                            </div>
                        ) : (
                            <div className="space-y-2">
                                {keys.map(k => (
                                    <div key={k.id} className="flex items-center gap-3 p-3 rounded-xl border border-sw-border hover:border-sw-red transition-colors">
                                        <div className="w-9 h-9 rounded-xl bg-sw-red-soft flex items-center justify-center text-sw-red flex-shrink-0">
                                            <i className="fas fa-key" />
                                        </div>
                                        <div className="flex-1 min-w-0">
                                            <div className="font-semibold text-slate-900 text-sm truncate">{k.name}</div>
                                            <div className="text-xs text-slate-500 mt-0.5 flex items-center gap-1.5">
                                                <code className="font-mono">{k.key_prefix}…</code>
                                                {!k.is_active && <span className="sw-badge sw-badge-neutral">Inactif</span>}
                                            </div>
                                        </div>
                                        <button onClick={() => openModal(<KeyDetailModal apikey={k} onDelete={() => { closeModal(); deleteKey(k.id); }} />)}
                                            className="text-slate-400 hover:text-slate-700 px-2">
                                            <i className="fas fa-ellipsis-vertical" />
                                        </button>
                                    </div>
                                ))}
                            </div>
                        )}
                    </div>
                </div>

                {/* History */}
                {serviceId === 'sms' && <SmsHistoryCard rows={history} />}
                {serviceId === 'agents' && <AgentsHistoryCard rows={history} />}
                {serviceId === 'maps' && <MapsTesterCard />}

                {/* Documentation hint */}
                <div className="sw-card p-4 flex gap-3 items-start">
                    <i className="fas fa-circle-info text-sw-red text-lg mt-0.5" />
                    <div className="flex-1 text-sm text-slate-600">
                        Utilisez votre clé en ajoutant l'en-tête <code className="sw-mono">Authorization: Bearer …</code> dans vos requêtes vers <code className="sw-mono">{service.endpoint}</code>.
                    </div>
                </div>
            </div>
        </div>
    );
};

// =================== CREDIT PANEL ===================
const CreditPanel = ({ service, data, onRecharge }) => {
    if (!data) {
        return <div className="sw-card p-5"><SkeletonRows count={2} height="h-6" /></div>;
    }
    const balance = data.balance || 0;
    const lastPack = data.last_pack_units || 0;
    const pct = lastPack > 0 ? Math.min(100, Math.round((balance / lastPack) * 100)) : 0;
    const level = data.level;
    const colors = { ok: '#16a34a', low: '#ca8a04', very_low: '#ea580c', empty: '#dc2626' };
    const c = colors[level] || '#94a3b8';
    const labels = { ok: 'OK', low: 'Bas', very_low: 'Très bas', empty: 'Épuisé' };
    const unit = service === 'sms' ? 'SMS' : 'requêtes';

    return (
        <div className="sw-card p-5">
            <div className="flex items-baseline justify-between mb-1">
                <div className="text-xs uppercase tracking-wider font-bold text-slate-400">Solde</div>
                <span className="sw-badge" style={{ background: `${c}20`, color: c }}>{labels[level]}</span>
            </div>
            <div className="text-4xl font-extrabold text-slate-900 leading-none">{balance}</div>
            <div className="text-xs text-slate-500 mt-1">{unit} restants</div>

            <div className="mt-4">
                <div className="flex justify-between text-xs text-slate-500 mb-1">
                    <span>Dernier pack : {lastPack} {unit}</span>
                    <span>{pct}%</span>
                </div>
                <div className="h-2 bg-slate-100 rounded-full overflow-hidden">
                    <div className="h-full transition-all" style={{ width: `${pct}%`, backgroundColor: c }} />
                </div>
                <div className="text-xs text-slate-400 mt-2">
                    {data.last_recharge_at ? `Dernière recharge : ${fmtDate(data.last_recharge_at)}` : 'Aucune recharge'}
                </div>
            </div>

            <button onClick={onRecharge} className="sw-btn sw-btn-primary w-full mt-4">
                <i className="fas fa-bolt" /> Recharger
            </button>

            {data.transactions && data.transactions.length > 0 && (
                <div className="mt-4 pt-3 border-t border-slate-100">
                    <div className="text-xs uppercase tracking-wider font-bold text-slate-400 mb-2">Mouvements récents</div>
                    <div className="space-y-1.5 max-h-48 overflow-auto sw-scroll">
                        {data.transactions.slice(0, 8).map(t => (
                            <div key={t.id} className="flex items-center justify-between text-sm py-1">
                                <div className="flex items-center gap-2 min-w-0">
                                    <strong style={{ color: t.amount > 0 ? '#16a34a' : '#dc2626' }}>
                                        {t.amount > 0 ? '+' : ''}{t.amount}
                                    </strong>
                                    <span className="text-slate-500 truncate">{t.description || t.type}</span>
                                </div>
                                <span className="text-xs text-slate-400 flex-shrink-0">{fmtDate(t.created_at)}</span>
                            </div>
                        ))}
                    </div>
                </div>
            )}
        </div>
    );
};

// =================== RECHARGE MODAL (Stripe) ===================
const RechargeModal = ({ service, onClose }) => {
    const { showToast } = useApp();
    const [packs, setPacks] = useState(null);
    const [loadingPack, setLoadingPack] = useState(null);

    useEffect(() => {
        apiFetch(`/api/${service}/packs`).then(d => setPacks(d?.packs || []));
    }, [service]);

    const checkout = async (packId) => {
        if (loadingPack) return;
        setLoadingPack(packId);
        try {
            sessionStorage.setItem('pendingRechargeService', service);
            const d = await apiFetch(`/api/${service}/recharge`, {
                method: 'POST',
                body: JSON.stringify({ pack_id: packId })
            });
            if (d?.success && d.checkout_url) {
                window.location.href = d.checkout_url;
                return;
            }
            if (d?.success && d.added) {
                showToast(`+${d.added} crédits ajoutés`, 'success');
                onClose();
                return;
            }
            throw new Error(d?.error || 'Erreur');
        } catch (e) {
            showToast(`Erreur : ${e.message || 'Recharge échouée'}`, 'error');
            setLoadingPack(null);
        }
    };

    const unit = service === 'sms' ? 'SMS' : 'requêtes';

    return (
        <>
            <ModalHeader title={`Recharger ${service === 'sms' ? 'SMS' : 'requêtes IA'}`}
                subtitle="Paiement sécurisé via Stripe" />
            <div className="p-5 space-y-3">
                {packs === null ? <SkeletonRows count={5} /> : packs.length === 0 ? (
                    <p className="text-center py-6 text-slate-400">Aucun pack disponible</p>
                ) : packs.map(p => {
                    const total = p.units + (p.bonus_units || 0);
                    const perUnit = (p.price_cents / 100) / total;
                    const isLoading = loadingPack === p.id;
                    return (
                        <div key={p.id} className={`border rounded-2xl p-4 transition-all ${p.bonus_units > 0 ? 'border-amber-300 bg-amber-50/40' : 'border-sw-border'}`}>
                            <div className="flex items-baseline justify-between mb-1">
                                <div className="font-bold text-slate-900">{p.name}</div>
                                <div className="text-xl font-extrabold text-sw-red-dark">{fmtCHF(p.price_cents)}</div>
                            </div>
                            <div className="text-sm text-slate-500 mb-3">
                                <strong>{total} {unit}</strong>
                                {p.bonus_units > 0 && <span className="text-amber-700 font-semibold"> · {p.bonus_units} bonus</span>}
                                <span className="text-xs text-slate-400 block mt-0.5">~ {perUnit.toFixed(perUnit < 0.1 ? 3 : 2)} CHF / {unit.replace(/s$/, '')}</span>
                            </div>
                            <button onClick={() => checkout(p.id)} disabled={!!loadingPack}
                                className="sw-btn sw-btn-primary w-full">
                                {isLoading ? <><i className="fas fa-spinner fa-spin" /> Redirection…</> : <><i className="fas fa-lock" /> Payer</>}
                            </button>
                        </div>
                    );
                })}
                <p className="text-xs text-center text-slate-400 pt-2">
                    <i className="fas fa-shield-halved" /> Paiement chiffré · Crédits ajoutés automatiquement après paiement
                </p>
            </div>
        </>
    );
};

// =================== KEY MODALS ===================
const CreateKeyModal = ({ forcedService, onClose, onCreated }) => {
    const { showToast } = useApp();
    const [name, setName] = useState('');
    const [service, setService] = useState(forcedService || 'sms');
    const [creating, setCreating] = useState(false);
    const [result, setResult] = useState(null);

    const create = async (e) => {
        e.preventDefault();
        if (!name || creating) return;
        setCreating(true);
        const d = await apiFetch('/api/keys', { method: 'POST', body: JSON.stringify({ name, service }) });
        if (d?.success) {
            setResult(d.key);
        } else {
            showToast(d?.error || 'Erreur', 'error');
            setCreating(false);
        }
    };

    const copyAndClose = () => {
        if (result?.key) navigator.clipboard.writeText(result.key);
        showToast('Clé copiée', 'success');
        onCreated && onCreated();
    };

    if (result) {
        return (
            <>
                <ModalHeader title="Clé créée" subtitle="Copiez-la maintenant — elle ne sera plus visible ensuite" onClose={() => onCreated && onCreated()} />
                <div className="p-5 space-y-3">
                    <div className="bg-amber-50 border border-amber-200 rounded-xl p-3 text-sm text-amber-900 flex gap-2">
                        <i className="fas fa-triangle-exclamation mt-0.5" />
                        <span>Cette clé n'est affichée qu'une seule fois. Sauvegardez-la dans un endroit sûr.</span>
                    </div>
                    <div className="bg-slate-900 text-emerald-300 font-mono text-sm p-4 rounded-xl break-all select-all">
                        {result.key}
                    </div>
                    <button onClick={copyAndClose} className="sw-btn sw-btn-primary w-full">
                        <i className="fas fa-copy" /> Copier et terminer
                    </button>
                </div>
            </>
        );
    }

    return (
        <>
            <ModalHeader title="Nouvelle clé API" />
            <form onSubmit={create} className="p-5 space-y-4">
                <div>
                    <label className="text-xs font-bold uppercase tracking-wider text-slate-500 block mb-1.5">Nom</label>
                    <input value={name} onChange={e => setName(e.target.value)} placeholder="Ex. Site web prod"
                        className="sw-input" required autoFocus />
                </div>
                <div>
                    <label className="text-xs font-bold uppercase tracking-wider text-slate-500 block mb-1.5">Service</label>
                    <select value={service} onChange={e => setService(e.target.value)} disabled={!!forcedService}
                        className="sw-input">
                        {SERVICES.map(s => <option key={s.id} value={s.id}>{s.label}</option>)}
                    </select>
                </div>
                <button type="submit" disabled={creating} className="sw-btn sw-btn-primary w-full">
                    {creating ? <><i className="fas fa-spinner fa-spin" /> Création…</> : <><i className="fas fa-plus" /> Créer la clé</>}
                </button>
            </form>
        </>
    );
};

const KeyDetailModal = ({ apikey, onDelete }) => {
    return (
        <>
            <ModalHeader title={apikey.name} subtitle={apikey.service} />
            <div className="p-5 space-y-3">
                <div>
                    <div className="text-xs font-bold uppercase tracking-wider text-slate-500 mb-1">Préfixe</div>
                    <code className="sw-mono block">{apikey.key_prefix}…</code>
                </div>
                <div>
                    <div className="text-xs font-bold uppercase tracking-wider text-slate-500 mb-1">Créée le</div>
                    <div className="text-sm">{fmtDate(apikey.created_at)}</div>
                </div>
                <div>
                    <div className="text-xs font-bold uppercase tracking-wider text-slate-500 mb-1">Statut</div>
                    {apikey.is_active
                        ? <span className="sw-badge sw-badge-success">Active</span>
                        : <span className="sw-badge sw-badge-neutral">Inactive</span>}
                </div>
                <button onClick={onDelete} className="sw-btn sw-btn-danger w-full mt-3">
                    <i className="fas fa-trash" /> Supprimer la clé
                </button>
            </div>
        </>
    );
};

// =================== SMS HISTORY ===================
const SmsHistoryCard = ({ rows }) => (
    <div className="sw-card overflow-hidden">
        <div className="px-4 py-3 border-b border-sw-border">
            <div className="font-bold text-slate-900">Historique SMS</div>
            <div className="text-xs text-slate-500">50 derniers envois</div>
        </div>
        <div className="divide-y divide-slate-100">
            {rows === null ? <div className="p-4"><SkeletonRows count={5} /></div>
                : rows.length === 0 ? <p className="text-center text-sm text-slate-400 py-8">Aucun SMS envoyé</p>
                : rows.map((s, i) => {
                    const status = SMS_STATUS_BADGES[s.status] || { label: s.status, className: 'sw-badge-neutral' };
                    const flag = s.country_code ? (COUNTRY_FLAGS[s.country_code] || '') : '';
                    return (
                        <div key={s.id || i} className="px-4 py-3 flex items-center gap-3">
                            <div className="w-8 text-center">{flag || '🌍'}</div>
                            <div className="flex-1 min-w-0">
                                <div className="text-sm font-semibold text-slate-900">{s.sender || '—'}</div>
                                <div className="text-xs text-slate-500 truncate font-mono">{s.to || ''}</div>
                            </div>
                            <div className="text-right">
                                <span className={`sw-badge ${status.className}`}>{status.label}</span>
                                <div className="text-xs text-slate-400 mt-0.5">
                                    {s.cost ? `${Number(s.cost).toFixed(3)} CHF` : ''}
                                </div>
                            </div>
                        </div>
                    );
                })}
        </div>
    </div>
);

const AgentsHistoryCard = ({ rows }) => (
    <div className="sw-card overflow-hidden">
        <div className="px-4 py-3 border-b border-sw-border">
            <div className="font-bold text-slate-900">Historique IA</div>
            <div className="text-xs text-slate-500">50 dernières requêtes</div>
        </div>
        <div className="divide-y divide-slate-100">
            {rows === null ? <div className="p-4"><SkeletonRows count={5} /></div>
                : rows.length === 0 ? <p className="text-center text-sm text-slate-400 py-8">Aucune requête</p>
                : rows.map((t, i) => (
                    <div key={t.id || i} className="px-4 py-3 flex items-center gap-3">
                        <div className="w-9 h-9 rounded-xl bg-violet-100 text-violet-600 flex items-center justify-center flex-shrink-0">
                            <i className="fas fa-robot" />
                        </div>
                        <div className="flex-1 min-w-0">
                            <div className="text-sm font-semibold text-slate-900 truncate">{t.description || 'Requête IA'}</div>
                            <div className="text-xs text-slate-500">{fmtDateTime(t.created_at)}</div>
                        </div>
                        <div className="text-right text-sm font-bold text-slate-700">−{Math.abs(t.amount)}</div>
                    </div>
                ))}
        </div>
    </div>
);

// =================== MAPS ===================
const MapsUsagePanel = () => {
    const [usage, setUsage] = useState(null);
    useEffect(() => {
        apiFetch('/api/maps/usage').then(d => setUsage(d?.success ? d : { stats: {} }));
    }, []);

    if (!usage) return <div className="sw-card p-5"><SkeletonRows count={2} height="h-12" /></div>;

    const stats = usage.stats || {};
    return (
        <div className="grid grid-cols-2 gap-3">
            <div className="sw-stat">
                <span className="sw-stat-label">Aujourd'hui</span>
                <span className="sw-stat-value">{stats.today ?? '—'}</span>
                <span className="sw-stat-hint">requêtes Maps</span>
            </div>
            <div className="sw-stat">
                <span className="sw-stat-label">Mois en cours</span>
                <span className="sw-stat-value">{stats.month ?? '—'}</span>
                <span className="sw-stat-hint">requêtes Maps</span>
            </div>
        </div>
    );
};

const MapsTesterCard = () => {
    const { openModal, closeModal } = useApp();
    return (
        <div className="sw-card p-4 flex items-center gap-3">
            <div className="w-10 h-10 rounded-xl bg-orange-100 text-orange-600 flex items-center justify-center flex-shrink-0">
                <i className="fas fa-vial" />
            </div>
            <div className="flex-1">
                <div className="font-semibold text-slate-900 text-sm">Tester l'API Maps</div>
                <div className="text-xs text-slate-500">Géocodage, recherche d'adresses, itinéraires</div>
            </div>
            <button onClick={() => openModal(<MapsTestModal onClose={closeModal} />)}
                className="sw-btn sw-btn-secondary !text-xs">
                Tester
            </button>
        </div>
    );
};

const MapsTestModal = ({ onClose }) => {
    const { showToast } = useApp();
    const [tab, setTab] = useState('geocode');
    const [addr, setAddr] = useState('');
    const [lat, setLat] = useState('46.5197');
    const [lng, setLng] = useState('6.6323');
    const [origin, setOrigin] = useState('Lausanne');
    const [dest, setDest] = useState('Genève');
    const [busy, setBusy] = useState(false);
    const [result, setResult] = useState(null);

    const call = async () => {
        setBusy(true); setResult(null);
        let path = '';
        if (tab === 'geocode') path = `/api/maps/geocode?address=${encodeURIComponent(addr)}&region=ch&language=fr`;
        else if (tab === 'reverse') path = `/api/maps/reverse-geocode?latitude=${lat}&longitude=${lng}`;
        else if (tab === 'places') path = `/api/maps/places?address=${encodeURIComponent(addr)}&countries=ch`;
        else if (tab === 'directions') path = `/api/maps/directions?origin=${encodeURIComponent(origin)}&destination=${encodeURIComponent(dest)}&mode=driving`;
        const d = await apiFetch(path);
        setResult(d);
        setBusy(false);
    };

    const tabs = [
        { id: 'geocode', label: 'Géocode' },
        { id: 'reverse', label: 'Reverse' },
        { id: 'places', label: 'Recherche' },
        { id: 'directions', label: 'Itinéraire' }
    ];

    return (
        <>
            <ModalHeader title="Tester Maps API" />
            <div className="p-5">
                <div className="flex gap-1 mb-4 bg-slate-100 p-1 rounded-xl text-xs font-semibold no-scrollbar overflow-x-auto">
                    {tabs.map(t => (
                        <button key={t.id} onClick={() => { setTab(t.id); setResult(null); }}
                            className={`flex-1 min-w-fit px-3 py-2 rounded-lg transition-colors ${tab === t.id ? 'bg-white shadow-sm text-slate-900' : 'text-slate-500'}`}>
                            {t.label}
                        </button>
                    ))}
                </div>

                {(tab === 'geocode' || tab === 'places') && (
                    <input value={addr} onChange={e => setAddr(e.target.value)} placeholder="Ex. Place du Molard, Genève" className="sw-input mb-3" />
                )}
                {tab === 'reverse' && (
                    <div className="grid grid-cols-2 gap-2 mb-3">
                        <input value={lat} onChange={e => setLat(e.target.value)} placeholder="Latitude" className="sw-input" />
                        <input value={lng} onChange={e => setLng(e.target.value)} placeholder="Longitude" className="sw-input" />
                    </div>
                )}
                {tab === 'directions' && (
                    <div className="space-y-2 mb-3">
                        <input value={origin} onChange={e => setOrigin(e.target.value)} placeholder="Départ" className="sw-input" />
                        <input value={dest} onChange={e => setDest(e.target.value)} placeholder="Destination" className="sw-input" />
                    </div>
                )}
                <button onClick={call} disabled={busy} className="sw-btn sw-btn-primary w-full">
                    {busy ? <><i className="fas fa-spinner fa-spin" /> Appel…</> : <><i className="fas fa-play" /> Lancer</>}
                </button>

                {result && (
                    <pre className="mt-4 bg-slate-900 text-emerald-300 text-xs p-3 rounded-xl overflow-auto max-h-72 sw-scroll">
                        {JSON.stringify(result, null, 2)}
                    </pre>
                )}
            </div>
        </>
    );
};

// =================== MODULES ===================
const ModulesView = () => {
    const { showToast, openModal, closeModal } = useApp();
    const [modules, setModules] = useState(null);

    const load = useCallback(async () => {
        const d = await apiFetch('/api/modules');
        setModules(d?.success ? (d.modules || []) : []);
    }, []);

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

    const toggle = async (m) => {
        const url = m.activated_at ? 'deactivate' : 'activate';
        const d = await apiFetch(`/api/modules/${m.id}/${url}`, { method: 'POST' });
        if (d?.success) { showToast(`Module ${m.activated_at ? 'désactivé' : 'activé'}`, 'success'); load(); }
        else showToast(d?.error || 'Erreur', 'error');
    };

    return (
        <div className="h-full overflow-auto sw-scroll pb-6">
            <Header title="Modules" subtitle="Apps métier prêtes à l'emploi" />
            <div className="px-4 pt-4 space-y-3">
                {modules === null ? <SkeletonRows count={4} height="h-28" /> : modules.length === 0 ? (
                    <div className="sw-card p-6 text-center">
                        <div className="text-4xl mb-2">🧩</div>
                        <p className="text-slate-500">Aucun module disponible</p>
                    </div>
                ) : modules.map(m => (
                    <div key={m.id} className="sw-card p-4 stagger-item">
                        <div className="flex items-start gap-3">
                            <div className="w-12 h-12 rounded-2xl bg-sw-red-soft text-sw-red flex items-center justify-center text-xl flex-shrink-0">
                                <i className={`fas ${m.icon || 'fa-cube'}`} />
                            </div>
                            <div className="flex-1 min-w-0">
                                <div className="font-bold text-slate-900">{m.name}</div>
                                <p className="text-sm text-slate-500 mt-0.5">{m.description}</p>
                                {m.url && (
                                    <a href={m.url} target="_blank" rel="noopener" className="text-xs text-sw-red font-semibold mt-1 inline-flex items-center gap-1">
                                        {m.url} <i className="fas fa-up-right-from-square text-[10px]" />
                                    </a>
                                )}
                            </div>
                        </div>
                        <div className="flex items-center justify-between mt-3 pt-3 border-t border-slate-100">
                            <div>
                                <div className="text-xs text-slate-400">Prix</div>
                                <div className="font-bold text-slate-900">{m.price_cents != null ? fmtCHF(m.price_cents) : 'Gratuit'} <small className="text-slate-400 font-normal">/ mois</small></div>
                            </div>
                            <button onClick={() => toggle(m)}
                                className={`sw-btn ${m.activated_at ? 'sw-btn-secondary' : 'sw-btn-primary'} !text-xs !py-2 !px-4`}>
                                {m.activated_at ? <><i className="fas fa-pause" /> Désactiver</> : <><i className="fas fa-bolt" /> Activer</>}
                            </button>
                        </div>
                    </div>
                ))}
            </div>
        </div>
    );
};

// =================== ACCOUNT ===================
const AccountView = () => {
    const { user, logout, setView, openModal, closeModal, showToast } = useApp();
    const [allKeys, setAllKeys] = useState(null);

    const loadKeys = useCallback(async () => {
        const d = await apiFetch('/api/keys');
        setAllKeys(d?.success ? (d.keys || []) : []);
    }, []);
    useEffect(() => { loadKeys(); }, [loadKeys]);

    const deleteKey = async (id) => {
        if (!confirm('Supprimer cette clé API ?')) return;
        const d = await apiFetch(`/api/keys/${id}`, { method: 'DELETE' });
        if (d?.success) { showToast('Clé supprimée', 'success'); loadKeys(); }
        else showToast(d?.error || 'Erreur', 'error');
    };

    return (
        <div className="h-full overflow-auto sw-scroll pb-6">
            <Header title="Compte" />
            <div className="px-4 pt-4 space-y-4">

                {/* Profile card */}
                <div className="sw-card p-5 flex items-center gap-4">
                    <div className="w-14 h-14 rounded-full bg-gradient-to-br from-sw-red to-sw-red-dark text-white flex items-center justify-center text-2xl font-extrabold">
                        {(user?.name || user?.email || '?')[0].toUpperCase()}
                    </div>
                    <div className="flex-1 min-w-0">
                        <div className="font-bold text-slate-900 truncate">{user?.name || user?.email}</div>
                        {user?.name && <div className="text-sm text-slate-500 truncate">{user?.email}</div>}
                        <div className="text-xs text-slate-400 mt-0.5">Compte créé {fmtDate(user?.created_at)}</div>
                    </div>
                </div>

                {/* Quick links */}
                <div className="sw-card divide-y divide-slate-100">
                    <SettingRow icon="fa-receipt" label="Factures & paiements" onClick={() => setView('billing')} />
                    <SettingRow icon="fa-bell" label="Notifications" hint="Bientôt" />
                    <SettingRow icon="fa-shield-halved" label="Sécurité" hint="Bientôt" />
                    <SettingRow icon="fa-headset" label="Support" onClick={() => window.location.href = 'mailto:hello@swissapp.org'} />
                </div>

                {/* All API keys */}
                <div className="sw-card overflow-hidden">
                    <div className="px-4 py-3 border-b border-sw-border flex items-center justify-between">
                        <div>
                            <div className="font-bold text-slate-900">Toutes mes clés API</div>
                            <div className="text-xs text-slate-500">{allKeys?.length || 0} clé(s)</div>
                        </div>
                        <button onClick={() => openModal(<CreateKeyModal onClose={closeModal} onCreated={() => { closeModal(); loadKeys(); }} />)}
                            className="sw-btn sw-btn-primary !py-2 !px-3 text-xs">
                            <i className="fas fa-plus" /> Nouvelle
                        </button>
                    </div>
                    <div className="p-3">
                        {allKeys === null ? <SkeletonRows count={3} /> : allKeys.length === 0 ? (
                            <p className="text-center py-6 text-slate-400 text-sm">Aucune clé créée</p>
                        ) : (
                            <div className="space-y-2">
                                {allKeys.map(k => {
                                    const svc = SERVICES.find(s => s.id === k.service);
                                    return (
                                        <div key={k.id} className="flex items-center gap-3 p-3 rounded-xl border border-sw-border">
                                            <div className="w-9 h-9 rounded-xl flex items-center justify-center text-white flex-shrink-0"
                                                style={{ backgroundColor: svc?.color || '#94a3b8' }}>
                                                <i className={`fas ${svc?.icon || 'fa-key'}`} />
                                            </div>
                                            <div className="flex-1 min-w-0">
                                                <div className="font-semibold text-slate-900 text-sm truncate">{k.name}</div>
                                                <div className="text-xs text-slate-500 mt-0.5 flex items-center gap-2">
                                                    <span className="capitalize">{k.service}</span>
                                                    <code className="font-mono text-[10px]">{k.key_prefix}…</code>
                                                </div>
                                            </div>
                                            <button onClick={() => deleteKey(k.id)} className="text-slate-400 hover:text-red-600 px-2">
                                                <i className="fas fa-trash" />
                                            </button>
                                        </div>
                                    );
                                })}
                            </div>
                        )}
                    </div>
                </div>

                {/* Logout */}
                <button onClick={logout} className="sw-btn sw-btn-secondary w-full">
                    <i className="fas fa-arrow-right-from-bracket" /> Se déconnecter
                </button>

                <p className="text-center text-xs text-slate-400 pt-2">Swissapp Space · v1.0</p>
            </div>
        </div>
    );
};

const SettingRow = ({ icon, label, hint, onClick }) => (
    <button onClick={onClick} disabled={!onClick}
        className={`w-full px-4 py-3.5 flex items-center gap-3 text-left ${onClick ? 'hover:bg-slate-50' : 'opacity-50 cursor-not-allowed'} transition-colors`}>
        <div className="w-9 h-9 rounded-xl bg-slate-100 text-slate-600 flex items-center justify-center flex-shrink-0">
            <i className={`fas ${icon}`} />
        </div>
        <div className="flex-1">
            <div className="font-semibold text-slate-900 text-sm">{label}</div>
            {hint && <div className="text-xs text-slate-400">{hint}</div>}
        </div>
        {onClick && <i className="fas fa-chevron-right text-slate-300 text-xs" />}
    </button>
);

// =================== BILLING ===================
const BillingView = () => {
    const { setView } = useApp();
    const [orders, setOrders] = useState(null);

    useEffect(() => {
        apiFetch('/api/orders').then(d => setOrders(d?.success ? (d.orders || []) : []));
    }, []);

    return (
        <div className="h-full overflow-auto sw-scroll pb-6">
            <Header title="Factures" subtitle="Historique des paiements" back={() => setView('account')} />
            <div className="px-4 pt-4">
                <div className="sw-card overflow-hidden">
                    {orders === null ? <div className="p-4"><SkeletonRows count={5} /></div>
                        : orders.length === 0 ? (
                            <div className="text-center py-12 text-slate-400">
                                <i className="fas fa-receipt text-4xl mb-3 opacity-40" />
                                <p>Aucune facture pour l'instant</p>
                            </div>
                        ) : (
                            <div className="divide-y divide-slate-100">
                                {orders.map(o => (
                                    <div key={o.id} className="px-4 py-3 flex items-center gap-3">
                                        <div className="w-10 h-10 rounded-xl bg-emerald-100 text-emerald-600 flex items-center justify-center flex-shrink-0">
                                            <i className="fas fa-check" />
                                        </div>
                                        <div className="flex-1 min-w-0">
                                            <div className="font-semibold text-slate-900 text-sm truncate">{o.description}</div>
                                            <div className="text-xs text-slate-500">{fmtDate(o.paid_at || o.created_at)}</div>
                                        </div>
                                        <div className="text-right">
                                            <div className="font-bold text-slate-900">{fmtCHF(o.amount)}</div>
                                            <span className={`sw-badge ${o.status === 'paid' ? 'sw-badge-success' : o.status === 'pending' ? 'sw-badge-warn' : 'sw-badge-neutral'}`}>{o.status}</span>
                                        </div>
                                    </div>
                                ))}
                            </div>
                        )}
                </div>
            </div>
        </div>
    );
};

// =================== BOTTOM NAV ===================
const BottomNav = () => {
    const { view, setView, setServiceView } = useApp();
    const items = [
        { id: 'home',     icon: 'fa-house',         label: 'Accueil' },
        { id: 'services', icon: 'fa-grid-2',        label: 'Services' },
        { id: 'modules',  icon: 'fa-puzzle-piece',  label: 'Modules' },
        { id: 'account',  icon: 'fa-user',          label: 'Compte' }
    ];
    return (
        <nav className="bottom-nav">
            {items.map(it => (
                <button key={it.id}
                    className={`bottom-nav-item ${view === it.id ? 'active' : ''}`}
                    onClick={() => { setView(it.id); if (it.id !== 'services') setServiceView(null); }}>
                    <i className={`fas ${it.icon}`} />
                    <span>{it.label}</span>
                </button>
            ))}
        </nav>
    );
};

// =================== MAIN APP ===================
const Main = () => {
    const { view } = useApp();
    return (
        <div className="h-full w-full flex flex-col">
            <div className="flex-1 overflow-hidden">
                {view === 'home'     && <HomeView />}
                {view === 'services' && <ServicesView />}
                {view === 'modules'  && <ModulesView />}
                {view === 'account'  && <AccountView />}
                {view === 'billing'  && <BillingView />}
            </div>
            <BottomNav />
        </div>
    );
};

const Root = () => {
    const { authed, bootLoading } = useApp();
    if (bootLoading) {
        return (
            <div className="h-full flex items-center justify-center bg-sw-bg">
                <div className="w-10 h-10 border-4 border-sw-red border-t-transparent rounded-full animate-spin" />
            </div>
        );
    }
    return authed ? <Main /> : <LoginScreen />;
};

// =================== MOUNT ===================
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(
    <AppProvider>
        <Root />
    </AppProvider>
);
