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

const CONFIG = { API_URL: 'https://api.vocal.ch' };

// ==================== ADMIN IMPERSONATION BOOTSTRAP ====================
// Admin can land here with ?impersonate_token=...&impersonate_user=BASE64.
// We persist them into localStorage and clean the URL before React boots.
(() => {
    try {
        const params = new URLSearchParams(window.location.search);
        const tok = params.get('impersonate_token');
        if (!tok) return;
        localStorage.setItem('vocal_my_token', tok);
        const userB64 = params.get('impersonate_user');
        if (userB64) {
            try {
                const u = JSON.parse(decodeURIComponent(escape(atob(userB64))));
                localStorage.setItem('vocal_my_user', JSON.stringify(u));
            } catch (e) {}
        }
        sessionStorage.setItem('vocal_my_impersonating', '1');
        const clean = window.location.pathname + window.location.hash;
        window.history.replaceState(null, '', clean);
    } catch (e) {}
})();

const LINE_TYPES = {
    forward: { label: 'Redirection', color: 'badge-info' },
    ivr: { label: 'Menu IVR', color: 'badge-warning' },
    voice_ai: { label: 'IA Vocale', color: 'badge-primary' },
    voicemail: { label: 'Messagerie', color: 'badge-gray' },
    browser: { label: 'Navigateur', color: 'badge-success' },
    link: { label: 'Envoi de lien', color: 'badge-purple' },
    webhook: { label: 'Webhook', color: 'badge-orange' },
    external_api: { label: 'API externe', color: 'badge-dark' },
};

const CALL_STATUS = {
    completed: { label: 'Terminé', color: 'badge-success' },
    ringing: { label: 'Sonne', color: 'badge-info' },
    'in-progress': { label: 'En cours', color: 'badge-info' },
    busy: { label: 'Occupé', color: 'badge-warning' },
    'no-answer': { label: 'Sans réponse', color: 'badge-warning' },
    failed: { label: 'Échoué', color: 'badge-danger' },
    canceled: { label: 'Annulé', color: 'badge-gray' },
    missed: { label: 'Manqué', color: 'badge-danger' },
};

// ==================== FORMATTERS ====================
function formatDate(d) { if (!d) return '-'; return new Date(d).toLocaleDateString('fr-CH', { day: '2-digit', month: '2-digit', year: 'numeric' }); }
function formatDateTime(d) { if (!d) return '-'; const x = new Date(d); return `${String(x.getDate()).padStart(2,'0')}/${String(x.getMonth()+1).padStart(2,'0')}/${x.getFullYear()} ${String(x.getHours()).padStart(2,'0')}:${String(x.getMinutes()).padStart(2,'0')}`; }
function formatTimeOnly(d) { if (!d) return ''; return new Date(d).toLocaleTimeString('fr-CH', { hour: '2-digit', minute: '2-digit' }); }
function formatDateShort(d) { if (!d) return ''; const x = new Date(d); return `${String(x.getDate()).padStart(2,'0')}/${String(x.getMonth()+1).padStart(2,'0')}/${String(x.getFullYear()).slice(-2)}`; }
function formatCurrency(amount, currency = 'CHF') { if (amount === null || amount === undefined) return '-'; return `${Number(amount).toFixed(2)} ${currency}`; }
function formatDuration(s) { if (!s) return '-'; const m = Math.floor(s/60); const sec = s%60; if (m === 0) return `${sec}s`; return `${m}m${sec>0?String(sec).padStart(2,'0')+'s':''}`; }
function formatRelative(d) {
    if (!d) return '-';
    const diff = (Date.now() - new Date(d).getTime()) / 1000;
    if (diff < 60) return 'à l\'instant';
    if (diff < 3600) return `il y a ${Math.floor(diff / 60)} min`;
    if (diff < 86400) return `il y a ${Math.floor(diff / 3600)} h`;
    if (diff < 604800) return `il y a ${Math.floor(diff / 86400)} j`;
    return formatDate(d);
}
function formatAmount(n, currency = 'CHF', sign = false) {
    if (n === null || n === undefined) return '-';
    const v = Number(n);
    const prefix = sign && v > 0 ? '+' : '';
    return `${prefix}${v.toFixed(2)} ${currency}`;
}

// ==================== I18N ====================
const I18N = {
  fr: {
    'nav.dashboard': 'Tableau de bord',
    'nav.lines': 'Lignes',
    'nav.calls': 'Appels',
    'nav.sms': 'SMS',
    'nav.bots': 'Bots vocaux',
    'nav.contacts': 'Contacts',
    'nav.proxy': 'Numéros temporaires',
    'nav.spam': 'Spam & blacklist',
    'nav.porting': 'Portabilité',
    'nav.api': 'Clés API',
    'nav.billing': 'Facturation',
    'nav.profile': 'Profil',
    'nav.routing': 'Routing avancé',
    'nav.nps': 'Satisfaction (NPS)',
    'nav.conversations': 'Conversations',
    'nav.voice_clones': 'Voix custom',
    'nav.studio': 'Studio voix',
    'nav.modules': 'Modules',
    'nav.live': 'Live (center)',
    'common.save': 'Enregistrer',
    'common.cancel': 'Annuler',
    'common.delete': 'Supprimer',
    'common.edit': 'Modifier',
    'common.add': 'Ajouter',
    'common.search': 'Rechercher',
    'common.loading': 'Chargement…',
    'common.empty': 'Aucun élément',
    'common.back': 'Retour',
    'lang.label': 'Langue',
  },
  de: {
    'nav.dashboard': 'Übersicht', 'nav.lines': 'Leitungen', 'nav.calls': 'Anrufe', 'nav.sms': 'SMS',
    'nav.bots': 'Sprachbots', 'nav.contacts': 'Kontakte', 'nav.proxy': 'Temporäre Nummern',
    'nav.spam': 'Spam & Blacklist', 'nav.porting': 'Portierung', 'nav.api': 'API-Schlüssel',
    'nav.billing': 'Abrechnung', 'nav.profile': 'Profil', 'nav.routing': 'Erweitertes Routing',
    'nav.nps': 'Zufriedenheit (NPS)', 'nav.conversations': 'Konversationen', 'nav.voice_clones': 'Eigene Stimmen',
    'nav.studio': 'Sprachstudio',
    'nav.modules': 'Module',
    'nav.live': 'Live (Center)',
    'common.save': 'Speichern', 'common.cancel': 'Abbrechen', 'common.delete': 'Löschen',
    'common.edit': 'Bearbeiten', 'common.add': 'Hinzufügen', 'common.search': 'Suchen',
    'common.loading': 'Lädt…', 'common.empty': 'Keine Einträge', 'common.back': 'Zurück',
    'lang.label': 'Sprache',
  },
  en: {
    'nav.dashboard': 'Dashboard', 'nav.lines': 'Lines', 'nav.calls': 'Calls', 'nav.sms': 'SMS',
    'nav.bots': 'Voice bots', 'nav.contacts': 'Contacts', 'nav.proxy': 'Temporary numbers',
    'nav.spam': 'Spam & blacklist', 'nav.porting': 'Porting', 'nav.api': 'API keys',
    'nav.billing': 'Billing', 'nav.profile': 'Profile', 'nav.routing': 'Advanced routing',
    'nav.nps': 'Satisfaction (NPS)', 'nav.conversations': 'Conversations', 'nav.voice_clones': 'Custom voices',
    'nav.studio': 'Voice studio',
    'nav.modules': 'Modules',
    'nav.live': 'Live (center)',
    'common.save': 'Save', 'common.cancel': 'Cancel', 'common.delete': 'Delete',
    'common.edit': 'Edit', 'common.add': 'Add', 'common.search': 'Search',
    'common.loading': 'Loading…', 'common.empty': 'No items', 'common.back': 'Back',
    'lang.label': 'Language',
  },
  it: {
    'nav.dashboard': 'Cruscotto', 'nav.lines': 'Linee', 'nav.calls': 'Chiamate', 'nav.sms': 'SMS',
    'nav.bots': 'Bot vocali', 'nav.contacts': 'Contatti', 'nav.proxy': 'Numeri temporanei',
    'nav.spam': 'Spam & blacklist', 'nav.porting': 'Portabilità', 'nav.api': 'Chiavi API',
    'nav.billing': 'Fatturazione', 'nav.profile': 'Profilo', 'nav.routing': 'Routing avanzato',
    'nav.nps': 'Soddisfazione (NPS)', 'nav.conversations': 'Conversazioni', 'nav.voice_clones': 'Voci personalizzate',
    'nav.studio': 'Studio voce',
    'nav.modules': 'Moduli',
    'nav.live': 'Live (center)',
    'common.save': 'Salva', 'common.cancel': 'Annulla', 'common.delete': 'Elimina',
    'common.edit': 'Modifica', 'common.add': 'Aggiungi', 'common.search': 'Cerca',
    'common.loading': 'Caricamento…', 'common.empty': 'Nessun elemento', 'common.back': 'Indietro',
    'lang.label': 'Lingua',
  },
};

const LANG_KEY = 'vocal_lang';
function getLang() { return localStorage.getItem(LANG_KEY) || (navigator.language || 'fr').slice(0,2); }
function setLang(l) { localStorage.setItem(LANG_KEY, l); window.dispatchEvent(new Event('lang-change')); }
function useLang() {
  const [lang, setLangState] = React.useState(getLang());
  React.useEffect(() => {
    const h = () => setLangState(getLang());
    window.addEventListener('lang-change', h);
    return () => window.removeEventListener('lang-change', h);
  }, []);
  return lang;
}
function t(key, lang) {
  const L = lang || getLang();
  return (I18N[L] && I18N[L][key]) || I18N.fr[key] || key;
}

// ==================== ICONS ====================
const Icons = {
    Phone: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"/></svg>),
    PhoneIn: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M21 3l-6 6m0 0V4m0 5h5M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"/></svg>),
    Home: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/></svg>),
    Key: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/></svg>),
    Send: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/></svg>),
    Chat: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"/></svg>),
    Settings: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>),
    Search: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>),
    Plus: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M12 4v16m8-8H4"/></svg>),
    Trash: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/></svg>),
    Refresh: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>),
    Menu: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M4 6h16M4 12h16M4 18h16"/></svg>),
    LogOut: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"/></svg>),
    Eye: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path strokeLinecap="round" strokeLinejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/></svg>),
    EyeOff: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"/></svg>),
    Copy: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2" strokeLinecap="round" strokeLinejoin="round"/><path strokeLinecap="round" strokeLinejoin="round" d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>),
    Check: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7"/></svg>),
    ChevronLeft: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M15 19l-7-7 7-7"/></svg>),
    ChevronRight: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M9 5l7 7-7 7"/></svg>),
    Clock: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>),
    Card: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"/></svg>),
    Wallet: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M21 12V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2h14a2 2 0 002-2v-3m-4-1a2 2 0 11-4 0 2 2 0 014 0z"/></svg>),
    Edit: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg>),
    Star: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z"/></svg>),
    AlertTriangle: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/></svg>),
    ArrowLeft: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18"/></svg>),
    Robot: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M12 2v3m-6 3h12a2 2 0 012 2v8a2 2 0 01-2 2H6a2 2 0 01-2-2v-8a2 2 0 012-2zm3 4h6m-6 4h.01m5.99 0H15M9 18h6"/></svg>),
    Calendar: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>),
    Sparkles: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z"/></svg>),
    Globe: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>),
    Document: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>),
    Play: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/><path strokeLinecap="round" strokeLinejoin="round" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>),
    Users: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/></svg>),
    Shield: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/></svg>),
    AlertCircle: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>),
    Moon: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/></svg>),
    Briefcase: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2 2v2m4 6h.01M5 20h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/></svg>),
    MessageSquare: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>),
    X: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12"/></svg>),
    ExternalLink: ({ className = "w-5 h-5" }) => (<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"><path strokeLinecap="round" strokeLinejoin="round" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg>),
};

const CallDirectionIcon = ({ direction }) => direction === 'outbound'
    ? <svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" style={{ color: '#2563eb' }}><path strokeLinecap="round" strokeLinejoin="round" d="M5 19l14-14m0 0h-10m10 0v10"/></svg>
    : <svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" style={{ color: '#16a34a' }}><path strokeLinecap="round" strokeLinejoin="round" d="M19 5L5 19m0 0h10M5 19V9"/></svg>;

const CallStatusDot = ({ status }) => {
    const colors = { completed: '#22c55e', ringing: '#3b82f6', 'in-progress': '#3b82f6', busy: '#f59e0b', 'no-answer': '#f59e0b', failed: '#ef4444', canceled: '#9ca3af', missed: '#ef4444' };
    return <span style={{ width: 8, height: 8, borderRadius: '50%', background: colors[status] || '#9ca3af', display: 'inline-block', flexShrink: 0 }} />;
};

// ==================== SKELETON ====================
const Skeleton = ({ width, height, className = '', style = {}, circle = false }) => (
    <span className={`skeleton ${circle ? 'skeleton-circle' : ''} ${className}`}
        style={{ width: typeof width === 'number' ? `${width}px` : (width || '100%'), height: typeof height === 'number' ? `${height}px` : (height || '0.85rem'), ...style }}>
        &nbsp;
    </span>
);
const SkeletonStatsGrid = ({ count = 4 }) => (
    <div className="skeleton-stats-grid">{Array.from({ length: count }).map((_, i) => (
        <div key={i} className="skeleton-stat-card">
            <Skeleton width={48} height={48} circle />
            <div style={{ flex: 1 }}><Skeleton width="55%" height={10} style={{ marginBottom: '0.5rem' }} /><Skeleton width="40%" height={20} /></div>
        </div>
    ))}</div>
);
const SkeletonTable = ({ rows = 8, cols = 6, hasHeader = true }) => (
    <div className="table-container">
        <table className="skeleton-table">
            {hasHeader && (
                <thead><tr>{Array.from({ length: cols }).map((_, c) => (
                    <th key={c} style={{ padding: '0.75rem 1rem', background: '#f8fafc', borderBottom: '1px solid var(--border)' }}>
                        <Skeleton width={`${50 + (c*7)%30}%`} height={9} />
                    </th>
                ))}</tr></thead>
            )}
            <tbody>{Array.from({ length: rows }).map((_, r) => (
                <tr key={r}>{Array.from({ length: cols }).map((_, c) => (
                    <td key={c}><Skeleton width={`${40 + ((r+c*13)%50)}%`} height={11} /></td>
                ))}</tr>
            ))}</tbody>
        </table>
    </div>
);
const SkeletonCards = ({ count = 6, columns = 3 }) => (
    <div style={{ display: 'grid', gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`, gap: '1rem' }}>
        {Array.from({ length: count }).map((_, i) => (
            <div key={i} className="card" style={{ padding: '1.25rem' }}>
                <Skeleton width="60%" height={14} style={{ marginBottom: '0.75rem' }} />
                <Skeleton width="100%" height={10} style={{ marginBottom: '0.4rem' }} />
                <Skeleton width="80%" height={10} />
            </div>
        ))}
    </div>
);
const useDebouncedValue = (value, delay = 300) => {
    const [debounced, setDebounced] = useState(value);
    useEffect(() => { const t = setTimeout(() => setDebounced(value), delay); return () => clearTimeout(t); }, [value, delay]);
    return debounced;
};

// ==================== API ====================
const api = {
    token: null,
    async req(path, options = {}) {
        const headers = { 'Content-Type': 'application/json', ...options.headers };
        if (this.token) headers['Authorization'] = `Bearer ${this.token}`;
        const resp = await fetch(`${CONFIG.API_URL}${path}`, { ...options, headers });
        return resp.json();
    },
    get(path) { return this.req(path); },
    post(path, body) { return this.req(path, { method: 'POST', body: JSON.stringify(body) }); },
    put(path, body) { return this.req(path, { method: 'PUT', body: JSON.stringify(body) }); },
    del(path) { return this.req(path, { method: 'DELETE' }); },
};

// ==================== NOTIFICATIONS ====================
const useNotifications = () => {
    const show = useCallback((message, type = 'info') => {
        const el = document.createElement('div');
        el.style.cssText = `position:fixed;bottom:1.5rem;right:1.5rem;z-index:9999;padding:0.875rem 1.25rem;border-radius:10px;font-size:0.875rem;font-weight:500;color:#fff;box-shadow:0 8px 24px rgba(0,0,0,0.18);transform:translateY(0);opacity:1;transition:all 0.3s ease;max-width:360px;font-family:Inter,sans-serif;`;
        const colors = { success: '#16a34a', error: '#dc2626', info: '#6366f1' };
        el.style.background = colors[type] || colors.info;
        el.textContent = message;
        document.body.appendChild(el);
        setTimeout(() => { el.style.opacity = '0'; el.style.transform = 'translateY(12px)'; setTimeout(() => el.remove(), 300); }, 4000);
    }, []);
    return useMemo(() => ({
        success: (m) => show(m, 'success'),
        error: (m) => show(m, 'error'),
        info: (m) => show(m, 'info'),
    }), [show]);
};

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

const AppProvider = ({ children }) => {
    const [user, setUser] = useState(() => {
        const saved = localStorage.getItem('vocal_my_user');
        const token = localStorage.getItem('vocal_my_token');
        if (saved && token) { api.token = token; return { ...JSON.parse(saved), token }; }
        return null;
    });
    const [view, setView] = useState(() => {
        const h = (window.location.hash || '').replace('#', '');
        return h && ['dashboard','lines','calls','sms','whatsapp','bots','contacts','proxy','spam','billing','subscriptions','porting','api-keys','settings','conversations','nps','voice-clones','studio','modules'].includes(h) ? h : 'dashboard';
    });
    const [sidebarOpen, setSidebarOpen] = useState(false);
    const [selectedLineId, setSelectedLineId] = useState(null);

    const notify = useNotifications();

    const login = useCallback((userData, token) => {
        api.token = token;
        setUser({ ...userData, token });
        localStorage.setItem('vocal_my_user', JSON.stringify(userData));
        localStorage.setItem('vocal_my_token', token);
        notify.success('Connexion réussie');
    }, [notify]);

    const logout = useCallback(() => {
        api.post('/auth/logout').catch(() => {});
        api.token = null;
        setUser(null);
        localStorage.removeItem('vocal_my_user');
        localStorage.removeItem('vocal_my_token');
        notify.info('Déconnexion réussie');
    }, [notify]);

    const refreshProfile = useCallback(async () => {
        try {
            const data = await api.get('/auth/me');
            if (data?.success && data.user) {
                setUser(prev => ({ ...prev, ...data.user, token: prev?.token }));
                localStorage.setItem('vocal_my_user', JSON.stringify(data.user));
            }
        } catch (e) {}
    }, []);

    const [selectedBotId, setSelectedBotId] = useState(null);
    const navigate = useCallback((v, opts = {}) => {
        setView(v);
        setSidebarOpen(false);
        if (opts.lineId) setSelectedLineId(opts.lineId);
        if (opts.botId) setSelectedBotId(opts.botId);
        if (v !== 'line-detail') {
            try { window.history.replaceState(null, '', `#${v}`); } catch (e) {}
        }
    }, []);

    const value = useMemo(() => ({
        user, view, sidebarOpen, setSidebarOpen, selectedLineId, setSelectedLineId,
        selectedBotId, setSelectedBotId,
        login, logout, navigate, notify, refreshProfile, setUser,
    }), [user, view, sidebarOpen, selectedLineId, selectedBotId, login, logout, navigate, notify, refreshProfile]);
    return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
};

// ==================== LOGIN ====================
const LoginScreen = () => {
    const { login } = useApp();
    const [email, setEmail] = useState('');
    const [code, setCode] = useState('');
    const [step, setStep] = useState('email');
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState('');

    useEffect(() => {
        const params = new URLSearchParams(window.location.search);
        const magicEmail = params.get('email');
        const magicCode = params.get('code');
        if (magicEmail && magicCode) {
            window.history.replaceState({}, '', window.location.pathname);
            setLoading(true);
            fetch(`${CONFIG.API_URL}/auth/verify-code`, {
                method: 'POST', headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ email: magicEmail, code: magicCode }),
            })
            .then(r => r.json())
            .then(data => {
                if (data.success && data.token) login(data.user || { email: magicEmail }, data.token);
                else { setEmail(magicEmail); setStep('code'); setError(data.error || 'Lien expiré, entrez le code manuellement'); }
            })
            .catch(() => { setEmail(magicEmail); setStep('code'); setError('Erreur réseau'); })
            .finally(() => setLoading(false));
        }
    }, []);

    const handleSendCode = async (e) => {
        e.preventDefault(); if (!email) return;
        setLoading(true); setError('');
        try {
            const resp = await fetch(`${CONFIG.API_URL}/auth/request-code`, {
                method: 'POST', headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ email }),
            });
            const data = await resp.json();
            if (data.success) setStep('code');
            else setError(data.error || 'Erreur');
        } catch (e) { setError('Erreur réseau'); }
        finally { setLoading(false); }
    };

    const handleVerify = async (e) => {
        e.preventDefault(); if (!code) return;
        setLoading(true); setError('');
        try {
            const resp = await fetch(`${CONFIG.API_URL}/auth/verify-code`, {
                method: 'POST', headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ email, code }),
            });
            const data = await resp.json();
            if (data.success && data.token) login(data.user || { email }, data.token);
            else setError(data.error || 'Code invalide');
        } catch (e) { setError('Erreur réseau'); }
        finally { setLoading(false); }
    };

    const features = [
        { icon: '📊', title: 'Statistiques en temps réel', desc: 'Suivez vos appels, SMS et coûts' },
        { icon: '📞', title: 'Vos lignes', desc: 'Consultez la configuration de vos lignes' },
        { icon: '🔑', title: 'Clés API', desc: 'Gérez vos accès pour intégrations tierces' },
        { icon: '⚙️', title: 'Self-service', desc: 'Espace personnel sécurisé' },
    ];

    return (
        <div className="login-split">
            <div className="login-form-side">
                <div className="login-form-inner">
                    <div className="login-brand">
                        <img src="assets/img/vocal-logotype.svg" alt="Vocal" style={{ height: '36px' }} />
                    </div>

                    {step === 'email' ? (
                        <form onSubmit={handleSendCode} className="login-form">
                            <h1 className="login-title" style={{ textAlign: 'center', marginBottom: '0.5rem' }}>Mon Espace Vocal</h1>
                            <p style={{ textAlign: 'center', color: 'var(--text-muted)', fontSize: '0.875rem', marginBottom: '2rem' }}>
                                Recevez un lien magique de connexion par email
                            </p>
                            <div className="form-group">
                                <label className="form-label">Adresse email</label>
                                <input type="email" value={email} onChange={(e) => setEmail(e.target.value)}
                                    placeholder="vous@exemple.com" className="form-input" autoFocus />
                            </div>
                            {error && <p style={{ color: '#dc2626', fontSize: '0.875rem', margin: '0 0 1rem' }}>{error}</p>}
                            <button type="submit" disabled={loading || !email} className="btn btn-primary" style={{ width: '100%' }}>
                                {loading ? 'Envoi...' : 'Recevoir le lien'}
                            </button>
                            <p style={{ marginTop: '1.5rem', textAlign: 'center', fontSize: '0.75rem', color: 'var(--text-muted)' }}>
                                Pas de mot de passe : un email suffit. Votre compte est créé automatiquement.
                            </p>
                        </form>
                    ) : (
                        <form onSubmit={handleVerify} className="login-form">
                            <h1 className="login-title" style={{ textAlign: 'center', marginBottom: '0.5rem' }}>Vérification</h1>
                            <p style={{ textAlign: 'center', color: 'var(--text-muted)', fontSize: '0.875rem', marginBottom: '2rem' }}>
                                Code envoyé à <strong>{email}</strong>
                            </p>
                            <div className="form-group" style={{ textAlign: 'center' }}>
                                <input type="text" value={code} onChange={(e) => setCode(e.target.value)}
                                    placeholder="000000" className="form-code-input" maxLength="6" autoFocus />
                            </div>
                            {error && <p style={{ color: '#dc2626', fontSize: '0.875rem', margin: '0 0 1rem', textAlign: 'center' }}>{error}</p>}
                            <button type="submit" disabled={loading || code.length < 4} className="btn btn-primary" style={{ width: '100%', marginBottom: '0.75rem' }}>
                                {loading ? 'Vérification...' : 'Se connecter'}
                            </button>
                            <button type="button" onClick={() => { setStep('email'); setCode(''); setError(''); }} className="btn btn-secondary" style={{ width: '100%' }}>
                                Retour
                            </button>
                        </form>
                    )}
                </div>
            </div>

            <div className="login-visual-side">
                <div className="login-visual-content">
                    <h2>Mon Espace Vocal</h2>
                    <p style={{ marginBottom: '2.5rem' }}>Pilotez votre téléphonie cloud depuis un seul endroit</p>
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem', textAlign: 'left' }}>
                        {features.map((f, i) => (
                            <div key={i} style={{ background: 'rgba(255,255,255,0.12)', borderRadius: '12px', padding: '1rem' }}>
                                <div style={{ fontSize: '1.5rem', marginBottom: '0.5rem' }}>{f.icon}</div>
                                <div style={{ fontWeight: 600, fontSize: '0.875rem', marginBottom: '0.25rem' }}>{f.title}</div>
                                <div style={{ fontSize: '0.75rem', opacity: 0.8 }}>{f.desc}</div>
                            </div>
                        ))}
                    </div>
                </div>
            </div>
        </div>
    );
};

// ==================== SIDEBAR ====================
const Sidebar = () => {
    const { user, view, sidebarOpen, setSidebarOpen, navigate, logout } = useApp();
    const lang = useLang();
    const items = [
        { id: 'dashboard', label: t('nav.dashboard', lang), icon: Icons.Home, section: 'main' },
        { id: 'lines', label: t('nav.lines', lang), icon: Icons.Phone, section: 'main' },
        { id: 'calls', label: t('nav.calls', lang), icon: Icons.PhoneIn, section: 'main' },
        { id: 'sms', label: t('nav.sms', lang), icon: Icons.Send, section: 'main' },
        { id: 'whatsapp', label: 'WhatsApp', icon: Icons.Chat, section: 'main' },
        { id: 'bots', label: t('nav.bots', lang), icon: Icons.Robot, section: 'main' },
        { id: 'voice-clones', label: t('nav.voice_clones', lang), icon: Icons.Sparkles, section: 'main' },
        { id: 'studio', label: t('nav.studio', lang), icon: Icons.Sparkles, section: 'main' },
        { id: 'contacts', label: t('nav.contacts', lang), icon: Icons.Users, section: 'crm' },
        { id: 'conversations', label: t('nav.conversations', lang), icon: Icons.MessageSquare, section: 'crm' },
        { id: 'nps', label: t('nav.nps', lang), icon: Icons.AlertCircle, section: 'crm' },
        { id: 'proxy', label: t('nav.proxy', lang), icon: Icons.Shield, section: 'crm' },
        { id: 'spam', label: t('nav.spam', lang), icon: Icons.AlertCircle, section: 'crm' },
        { id: 'billing', label: t('nav.billing', lang), icon: Icons.Wallet, section: 'billing' },
        { id: 'subscriptions', label: 'Abonnements', icon: Icons.Card, section: 'billing' },
        { id: 'modules', label: t('nav.modules', lang), icon: Icons.Sparkles, section: 'billing' },
        { id: 'porting', label: t('nav.porting', lang), icon: Icons.Refresh, section: 'billing' },
        { id: 'api-keys', label: t('nav.api', lang), icon: Icons.Key, section: 'tools' },
        { id: 'settings', label: 'Paramètres', icon: Icons.Settings, section: 'tools' },
    ];
    const sections = {
        main: 'ESPACE PERSONNEL',
        crm: 'RELATIONS',
        billing: 'FACTURATION',
        tools: 'OUTILS',
    };
    const grouped = Object.entries(sections).map(([key, label]) => ({
        label, items: items.filter(i => i.section === key),
    }));
    return (
        <>
            {sidebarOpen && (<div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.3)', zIndex: 99 }} onClick={() => setSidebarOpen(false)} />)}
            <aside className={`sidebar ${sidebarOpen ? 'open' : ''}`}>
                <div className="sidebar-header">
                    <img src="assets/img/vocal-logotype.svg" alt="Vocal" className="logo" />
                </div>
                <nav className="sidebar-nav">
                    {grouped.map(group => (
                        <div className="nav-section" key={group.label}>
                            <div className="nav-section-title">{group.label}</div>
                            {group.items.map(item => (
                                <button key={item.id} className={`nav-item ${view === item.id || (item.id === 'lines' && view === 'line-detail') ? 'active' : ''}`} onClick={() => navigate(item.id)}>
                                    <item.icon className="nav-icon" />
                                    {item.label}
                                </button>
                            ))}
                        </div>
                    ))}
                </nav>
                <div className="sidebar-footer">
                    <TopbarControls />
                    <div className="user-info">
                        <div className="user-avatar">{(user?.name || user?.email || 'U')[0].toUpperCase()}</div>
                        <div className="user-details">
                            <div className="user-name">{user?.name || user?.client?.name || 'Mon compte'}</div>
                            <div className="user-role">{user?.email}</div>
                        </div>
                        <button onClick={logout} title="Déconnexion" style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '0.5rem', color: 'var(--text-muted)' }}>
                            <Icons.LogOut className="w-5 h-5" />
                        </button>
                    </div>
                </div>
            </aside>
        </>
    );
};

// ==================== TOPBAR CONTROLS (lang + live center) ====================
const TopbarControls = () => {
    const lang = useLang();
    return (
        <div style={{ display: 'flex', gap: '0.4rem', alignItems: 'center', marginBottom: '0.6rem', flexWrap: 'wrap' }}>
            <select
                aria-label={t('lang.label', lang)}
                title={t('lang.label', lang)}
                value={lang}
                onChange={(e) => setLang(e.target.value)}
                className="form-input"
                style={{ flex: '1 1 auto', minWidth: 80, padding: '0.4rem 0.5rem', fontSize: '0.8rem', marginBottom: 0 }}
            >
                <option value="fr">FR</option>
                <option value="de">DE</option>
                <option value="en">EN</option>
                <option value="it">IT</option>
            </select>
            <button
                type="button"
                title={t('nav.live', lang)}
                onClick={() => window.open('https://center.vocal.ch', '_blank', 'noopener')}
                className="btn btn-secondary btn-sm"
                style={{ padding: '0.4rem 0.6rem', fontSize: '0.75rem', whiteSpace: 'nowrap' }}
            >
                <Icons.ExternalLink className="w-4 h-4" /> {t('nav.live', lang)}
            </button>
        </div>
    );
};

const MobileHeader = () => {
    const { setSidebarOpen } = useApp();
    return (
        <div className="mobile-header" style={{ display: 'none', position: 'sticky', top: 0, zIndex: 50, height: 'var(--header-height)', padding: '0 1rem', background: 'var(--bg-white)', borderBottom: '1px solid var(--border)', alignItems: 'center', gap: '0.75rem' }}>
            <button onClick={() => setSidebarOpen(true)} style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '0.5rem' }}>
                <Icons.Menu className="w-6 h-6" />
            </button>
            <img src="assets/img/vocal-logotype.svg" alt="Vocal" style={{ height: '28px' }} />
            <span style={{ fontWeight: 700, fontSize: '1rem' }}>Mon Espace</span>
        </div>
    );
};

// ==================== DASHBOARD ====================
const DashboardView = () => {
    const { user, navigate, notify } = useApp();
    const [stats, setStats] = useState(null);
    const [balance, setBalance] = useState(null);
    const [recent, setRecent] = useState([]);
    const [loading, setLoading] = useState(true);
    const [refreshing, setRefreshing] = useState(false);

    const load = useCallback(async (background = false) => {
        if (background) setRefreshing(true); else setLoading(true);
        try {
            const [s, c, b] = await Promise.all([
                api.get('/my/stats'),
                api.get('/my/calls?page=1&limit=5'),
                api.get('/my/billing/balance'),
            ]);
            if (s?.error) {
                notify.error(s.error);
                setStats({ lines: { total: 0, active: 0 }, calls: { total: 0, today: 0, month: 0, total_duration: 0, total_cost: 0 }, api_keys: { total: 0 } });
            } else {
                setStats(s);
            }
            setBalance(b);
            setRecent(c?.calls || []);
        } catch (e) { notify.error('Erreur chargement dashboard'); }
        finally { setLoading(false); setRefreshing(false); }
    }, [notify]);

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

    const cards = stats ? [
        { label: 'Mes lignes actives', value: `${stats.lines?.active || 0} / ${stats.lines?.total || 0}`, icon: Icons.Phone, color: 'green', view: 'lines' },
        { label: 'Appels ce mois', value: stats.calls?.month || 0, icon: Icons.PhoneIn, color: 'blue', view: 'calls' },
        { label: 'Coût total', value: formatCurrency(stats.calls?.total_cost || 0), icon: Icons.Card, color: 'purple', view: 'calls' },
        { label: 'Clés API', value: stats.api_keys?.total || 0, icon: Icons.Key, color: 'orange', view: 'api-keys' },
    ] : [];

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Bonjour, {user?.name || user?.client?.name || user?.email?.split('@')[0]}</h1>
                    <p className="page-subtitle">Vue d'ensemble de votre activité Vocal</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={() => load(true)} disabled={refreshing}>
                        <Icons.Refresh className="w-4 h-4" /> {refreshing ? 'Mise à jour...' : 'Actualiser'}
                    </button>
                </div>
            </div>
            <div className="page-content">
                {/* Mini-widget solde */}
                {!loading && balance && (
                    <button onClick={() => navigate('billing')} className="card"
                        style={{ width: '100%', textAlign: 'left', cursor: 'pointer', padding: '1.25rem 1.5rem', marginBottom: '1.5rem', background: balance.balance < (balance.critical_threshold || 1) ? 'linear-gradient(135deg, #fef2f2, #fef3c7)' : balance.balance < (balance.low_threshold || 5) ? 'linear-gradient(135deg, #fef3c7, #fffbeb)' : 'linear-gradient(135deg, #eef2ff, #f0f9ff)', border: '1px solid #c7d2fe', display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: '1rem' }}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
                            <div style={{ width: 48, height: 48, borderRadius: 12, background: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--primary)' }}>
                                <Icons.Wallet className="w-6 h-6" />
                            </div>
                            <div>
                                <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)', textTransform: 'uppercase', fontWeight: 600, letterSpacing: '0.05em' }}>Solde wallet</div>
                                <div style={{ fontSize: '1.5rem', fontWeight: 800, color: balance.balance < (balance.critical_threshold || 1) ? '#dc2626' : balance.balance < (balance.low_threshold || 5) ? '#d97706' : 'var(--text-main)' }}>
                                    {(balance.balance || 0).toFixed(2)} {balance.currency || 'CHF'}
                                </div>
                            </div>
                        </div>
                        <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', color: 'var(--primary)', fontWeight: 600, fontSize: '0.875rem' }}>
                            Recharger
                            <span>→</span>
                        </div>
                    </button>
                )}

                {loading ? (
                    <SkeletonStatsGrid count={4} />
                ) : (
                    <div className="stats-grid">
                        {cards.map((c, i) => (
                            <button key={i} className="stat-card" onClick={() => navigate(c.view)}
                                style={{ cursor: 'pointer', textAlign: 'left', border: '1px solid var(--border)', background: 'var(--bg-white)' }}>
                                <div className={`stat-icon ${c.color}`}><c.icon className="w-6 h-6" /></div>
                                <div>
                                    <div className="stat-label">{c.label}</div>
                                    <div className="stat-value">{c.value}</div>
                                </div>
                            </button>
                        ))}
                    </div>
                )}

                <div className="card" style={{ marginBottom: '1.5rem' }}>
                    <div style={{ padding: '1rem 1.25rem', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                        <h3 style={{ fontSize: '0.95rem', fontWeight: 700, margin: 0 }}>Derniers appels</h3>
                        <button className="btn btn-secondary btn-sm" onClick={() => navigate('calls')}>Voir tout</button>
                    </div>
                    {loading ? (
                        <SkeletonTable rows={5} cols={5} hasHeader={false} />
                    ) : recent.length === 0 ? (
                        <div style={{ padding: '3rem 2rem', textAlign: 'center', color: 'var(--text-muted)' }}>
                            <Icons.PhoneIn className="w-10 h-10" style={{ margin: '0 auto 0.75rem', opacity: 0.4 }} />
                            <p style={{ margin: 0, fontSize: '0.9rem' }}>Aucun appel récent</p>
                        </div>
                    ) : (
                        <div className="table-container">
                            <table className="data-table">
                                <thead><tr><th></th><th>Date</th><th>Appelant</th><th>Ligne</th><th>Statut</th><th style={{ textAlign: 'right' }}>Durée</th></tr></thead>
                                <tbody>
                                    {recent.map(call => {
                                        const st = CALL_STATUS[call.status] || { label: call.status, color: 'badge-gray' };
                                        return (
                                            <tr key={call.id}>
                                                <td style={{ width: 30 }}><CallDirectionIcon direction={call.direction} /></td>
                                                <td style={{ fontSize: '0.8rem' }}>
                                                    <div style={{ fontWeight: 500 }}>{formatDateShort(call.created_at)}</div>
                                                    <div style={{ fontSize: '0.7rem', color: 'var(--text-muted)' }}>{formatTimeOnly(call.created_at)}</div>
                                                </td>
                                                <td style={{ fontFamily: 'ui-monospace, monospace', fontSize: '0.8rem' }}>{call.from_number || '-'}</td>
                                                <td style={{ fontSize: '0.8rem' }}>{call.line_label || call.line_phone || '-'}</td>
                                                <td><div style={{ display: 'flex', alignItems: 'center', gap: '0.4rem' }}><CallStatusDot status={call.status} /><span style={{ fontSize: '0.8rem' }}>{st.label}</span></div></td>
                                                <td style={{ textAlign: 'right', fontSize: '0.8rem', fontFeatureSettings: '"tnum"' }}>{formatDuration(call.duration)}</td>
                                            </tr>
                                        );
                                    })}
                                </tbody>
                            </table>
                        </div>
                    )}
                </div>

                <div className="card">
                    <div style={{ padding: '1.25rem 1.5rem' }}>
                        <h3 style={{ fontSize: '0.95rem', fontWeight: 700, margin: '0 0 0.5rem' }}>Bienvenue sur Mon Espace Vocal</h3>
                        <p style={{ margin: '0 0 0.75rem', color: 'var(--text-muted)', fontSize: '0.85rem' }}>
                            Cet espace vous permet de consulter vos lignes, vos appels et de gérer vos clés API pour intégrer Vocal dans votre application.
                        </p>
                        <p style={{ margin: 0, fontSize: '0.8rem', color: 'var(--text-muted)' }}>
                            Pour ajouter une nouvelle ligne ou modifier la configuration, contactez votre administrateur Vocal.
                        </p>
                    </div>
                </div>
            </div>
        </>
    );
};

// ==================== LINES ====================
const LinesView = () => {
    const { notify, navigate } = useApp();
    const [lines, setLines] = useState([]);
    const [subs, setSubs] = useState([]);
    const [loading, setLoading] = useState(true);
    const [search, setSearch] = useState('');

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const [l, s] = await Promise.all([api.get('/my/lines'), api.get('/my/subscriptions')]);
            if (l?.error) notify.error(l.error);
            setLines(l?.lines || []);
            setSubs(s?.subscriptions || []);
        } catch (e) { notify.error('Erreur chargement lignes'); }
        finally { setLoading(false); }
    }, [notify]);

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

    const subByLine = useMemo(() => {
        const m = {};
        for (const s of subs) {
            if (!m[s.line_id] || new Date(s.created_at) > new Date(m[s.line_id].created_at)) m[s.line_id] = s;
        }
        return m;
    }, [subs]);

    const filtered = useMemo(() => {
        if (!search) return lines;
        const q = search.toLowerCase();
        return lines.filter(l => (l.phone_number || '').toLowerCase().includes(q) || (l.label || '').toLowerCase().includes(q) || (l.description || '').toLowerCase().includes(q));
    }, [lines, search]);

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Mes lignes</h1>
                    <p className="page-subtitle">{lines.length} ligne(s) configurée(s)</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={load}><Icons.Refresh className="w-4 h-4" /> Actualiser</button>
                </div>
            </div>
            <div className="page-content">
                <div style={{ marginBottom: '1rem', position: 'relative', maxWidth: '320px' }}>
                    <Icons.Search className="w-4 h-4" style={{ position: 'absolute', left: '0.75rem', top: '50%', transform: 'translateY(-50%)', color: 'var(--text-muted)' }} />
                    <input type="text" value={search} onChange={(e) => setSearch(e.target.value)}
                        placeholder="Rechercher une ligne..." className="form-input" style={{ paddingLeft: '2.25rem' }} />
                </div>

                {loading ? (
                    <SkeletonTable rows={5} cols={6} />
                ) : filtered.length === 0 ? (
                    <div className="card" style={{ padding: '4rem 2rem', textAlign: 'center' }}>
                        <Icons.Phone className="w-12 h-12" style={{ margin: '0 auto 1rem', opacity: 0.4, color: 'var(--text-muted)' }} />
                        <h3 style={{ margin: '0 0 0.5rem', fontWeight: 600 }}>Aucune ligne</h3>
                        <p style={{ margin: 0, color: 'var(--text-muted)', fontSize: '0.875rem' }}>
                            Vous n'avez pas encore de ligne assignée. Contactez l'équipe Vocal pour configurer votre numéro.
                        </p>
                        <a href="mailto:contact@vocal.ch" className="btn btn-primary btn-sm" style={{ marginTop: '1.25rem', display: 'inline-flex' }}>
                            Contacter Vocal
                        </a>
                    </div>
                ) : (
                    <div className="card" style={{ overflow: 'hidden' }}>
                        <div className="table-container">
                            <table className="data-table">
                                <thead>
                                    <tr>
                                        <th>Numéro</th>
                                        <th>Libellé</th>
                                        <th>Type</th>
                                        <th>Abonnement</th>
                                        <th style={{ textAlign: 'right' }}>Appels (mois)</th>
                                        <th style={{ textAlign: 'right' }}>Total</th>
                                        <th style={{ textAlign: 'center' }}>Statut</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {filtered.map(l => {
                                        const t = LINE_TYPES[l.type] || { label: l.type, color: 'badge-gray' };
                                        const sub = subByLine[l.id];
                                        const isSubActive = sub && (sub.status === 'active' || sub.status === 'trialing');
                                        return (
                                            <tr key={l.id} onClick={() => navigate('line-detail', { lineId: l.id })} style={{ cursor: 'pointer' }}>
                                                <td style={{ fontFamily: 'ui-monospace, monospace', fontWeight: 700, fontSize: '0.85rem' }}>{l.phone_number}</td>
                                                <td>
                                                    <div style={{ fontWeight: 500, fontSize: '0.85rem' }}>{l.label || '-'}</div>
                                                    {l.description && <div style={{ fontSize: '0.7rem', color: 'var(--text-muted)', marginTop: '0.15rem' }}>{l.description.length > 60 ? l.description.slice(0, 60) + '…' : l.description}</div>}
                                                </td>
                                                <td><span className={`badge ${t.color}`}>{t.label}</span></td>
                                                <td>
                                                    {sub ? (
                                                        <span className={`badge ${isSubActive ? 'badge-success' : (sub.status === 'past_due' ? 'badge-warning' : 'badge-gray')}`}>
                                                            {sub.billing_period === 'yearly' ? 'Annuel' : 'Mensuel'} • {isSubActive ? 'actif' : sub.status}
                                                        </span>
                                                    ) : <span className="badge badge-gray">Aucun</span>}
                                                </td>
                                                <td style={{ textAlign: 'right', fontWeight: 600, fontSize: '0.85rem', fontFeatureSettings: '"tnum"' }}>{l.month_calls || 0}</td>
                                                <td style={{ textAlign: 'right', fontSize: '0.85rem', color: 'var(--text-muted)', fontFeatureSettings: '"tnum"' }}>{l.total_calls || 0}</td>
                                                <td style={{ textAlign: 'center' }}>
                                                    <span className={`badge ${l.is_active ? 'badge-success' : 'badge-gray'}`}>{l.is_active ? 'Active' : 'Inactive'}</span>
                                                </td>
                                            </tr>
                                        );
                                    })}
                                </tbody>
                            </table>
                        </div>
                    </div>
                )}
            </div>
        </>
    );
};

// ==================== LINE DETAIL ====================
const DAY_LABELS = [
    { id: 'monday',    label: 'Lundi' },
    { id: 'tuesday',   label: 'Mardi' },
    { id: 'wednesday', label: 'Mercredi' },
    { id: 'thursday',  label: 'Jeudi' },
    { id: 'friday',    label: 'Vendredi' },
    { id: 'saturday',  label: 'Samedi' },
    { id: 'sunday',    label: 'Dimanche' },
];
function defaultBusinessHours() {
    const out = { holidays: [] };
    DAY_LABELS.forEach(d => {
        const isWeekend = d.id === 'saturday' || d.id === 'sunday';
        out[d.id] = { open: !isWeekend, from: '09:00', to: '18:00' };
    });
    return out;
}

const LineDetailView = () => {
    const { selectedLineId, navigate, notify } = useApp();
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [tab, setTab] = useState('summary');
    const [editMode, setEditMode] = useState(false);
    const [form, setForm] = useState({});
    const [saving, setSaving] = useState(false);

    const load = useCallback(async () => {
        if (!selectedLineId) return;
        setLoading(true);
        try {
            const d = await api.get(`/my/lines/${selectedLineId}`);
            if (d?.error) { notify.error(d.error); return; }
            setData(d);
            const parsedHours = (() => {
                try { return d.line.business_hours ? JSON.parse(d.line.business_hours) : defaultBusinessHours(); }
                catch (e) { return defaultBusinessHours(); }
            })();
            setForm({
                label: d.line.label || '',
                description: d.line.description || '',
                forward_number: d.line.forward_number || '',
                voicemail_email: d.line.voicemail_email || '',
                notification_number: d.line.notification_number || '',
                webhook_url: d.line.webhook_url || '',
                link_url: d.line.link_url || '',
                link_email: d.line.link_email || '',
                link_sms_sender: d.line.link_sms_sender || '',
                record_calls: !!d.line.record_calls,
                transcription_enabled: !!d.line.transcription_enabled,
                transcription_email: d.line.transcription_email || '',
                transcription_language: d.line.transcription_language || 'fr',
                business_hours_enabled: !!d.line.business_hours_enabled,
                business_hours: parsedHours,
                timezone: d.line.timezone || 'Europe/Zurich',
                out_of_hours_action: d.line.out_of_hours_action || 'message',
                out_of_hours_forward_number: d.line.out_of_hours_forward_number || '',
                out_of_hours_message: d.line.out_of_hours_message || '',
                voice_bot_id: d.line.voice_bot_id || null,
            });
        } catch (e) { notify.error('Erreur chargement ligne'); }
        finally { setLoading(false); }
    }, [selectedLineId, notify]);

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

    const save = async () => {
        setSaving(true);
        try {
            const payload = { ...form };
            if (payload.business_hours && typeof payload.business_hours === 'object') {
                payload.business_hours = JSON.stringify(payload.business_hours);
            }
            const r = await api.put(`/my/lines/${selectedLineId}`, payload);
            if (r?.error) notify.error(r.error);
            else { notify.success('Ligne mise à jour'); setEditMode(false); load(); }
        } catch (e) { notify.error('Erreur'); }
        finally { setSaving(false); }
    };

    if (loading || !data) {
        return (
            <>
                <div className="page-header">
                    <div>
                        <button className="btn btn-secondary btn-sm" onClick={() => navigate('lines')} style={{ marginBottom: '0.5rem' }}>
                            <Icons.ArrowLeft className="w-4 h-4" /> Retour
                        </button>
                        <h1 className="page-title">Chargement…</h1>
                    </div>
                </div>
                <div className="page-content"><SkeletonStatsGrid count={3} /></div>
            </>
        );
    }

    const { line, stats, subscription, recent_calls } = data;
    const lineMeta = LINE_TYPES[line.type] || { label: line.type, color: 'badge-gray' };

    return (
        <>
            <div className="page-header">
                <div>
                    <button className="btn btn-secondary btn-sm" onClick={() => navigate('lines')} style={{ marginBottom: '0.5rem' }}>
                        <Icons.ArrowLeft className="w-4 h-4" /> Mes lignes
                    </button>
                    <h1 className="page-title" style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
                        <span style={{ fontFamily: 'ui-monospace, monospace' }}>{line.phone_number}</span>
                        <span className={`badge ${line.is_active ? 'badge-success' : 'badge-gray'}`}>{line.is_active ? 'Active' : 'Inactive'}</span>
                        <span className={`badge ${lineMeta.color}`}>{lineMeta.label}</span>
                    </h1>
                    {line.label && <p className="page-subtitle">{line.label}</p>}
                </div>
                <div className="page-actions">
                    {(tab === 'config' || tab === 'hours' || tab === 'bot' || tab === 'dnd' || tab === 'vacation' || tab === 'callback' || tab === 'queue') && !editMode && (
                        <button className="btn btn-primary btn-sm" onClick={() => setEditMode(true)}>
                            <Icons.Edit className="w-4 h-4" /> Modifier
                        </button>
                    )}
                </div>
            </div>

            <div className="page-content">
                <div style={{ display: 'flex', gap: '0.5rem', marginBottom: '1.5rem', borderBottom: '1px solid var(--border)', flexWrap: 'wrap' }}>
                    {[
                        { id: 'summary', label: 'Résumé', icon: Icons.Home },
                        { id: 'config', label: 'Configuration', icon: Icons.Settings },
                        { id: 'hours', label: 'Horaires', icon: Icons.Calendar },
                        { id: 'dnd', label: 'Ne pas déranger', icon: Icons.Moon },
                        { id: 'vacation', label: 'Vacances', icon: Icons.Briefcase },
                        { id: 'callback', label: 'Rappel auto', icon: Icons.Refresh },
                        ...(line && line.type === 'queue' ? [{ id: 'queue', label: 'Agents', icon: Icons.Users }] : []),
                        { id: 'bot', label: 'Bot vocal', icon: Icons.Robot },
                        { id: 'routing', label: t('nav.routing'), icon: Icons.Sparkles },
                        { id: 'nps', label: t('nav.nps'), icon: Icons.AlertCircle },
                        { id: 'subscription', label: 'Abonnement', icon: Icons.Card },
                        { id: 'widget', label: 'Widget & API', icon: Icons.Key },
                    ].map(t => (
                        <button key={t.id} onClick={() => setTab(t.id)}
                            style={{ background: 'none', border: 'none', padding: '0.75rem 1rem', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '0.4rem', fontSize: '0.875rem', fontWeight: 500, color: tab === t.id ? 'var(--primary)' : 'var(--text-muted)', borderBottom: tab === t.id ? '2px solid var(--primary)' : '2px solid transparent', marginBottom: '-1px' }}>
                            <t.icon className="w-4 h-4" /> {t.label}
                        </button>
                    ))}
                </div>

                {tab === 'summary' && (
                    <>
                        <div className="stats-grid" style={{ marginBottom: '1.5rem' }}>
                            <div className="stat-card"><div className="stat-icon blue"><Icons.PhoneIn className="w-6 h-6" /></div><div><div className="stat-label">Total appels</div><div className="stat-value">{stats.total_calls || 0}</div></div></div>
                            <div className="stat-card"><div className="stat-icon green"><Icons.Phone className="w-6 h-6" /></div><div><div className="stat-label">Ce mois</div><div className="stat-value">{stats.month_calls || 0}</div></div></div>
                            <div className="stat-card"><div className="stat-icon purple"><Icons.Clock className="w-6 h-6" /></div><div><div className="stat-label">Durée totale</div><div className="stat-value">{formatDuration(stats.total_duration)}</div></div></div>
                            <div className="stat-card"><div className="stat-icon orange"><Icons.Card className="w-6 h-6" /></div><div><div className="stat-label">Coût total</div><div className="stat-value">{formatCurrency(stats.total_cost)}</div></div></div>
                        </div>
                        <div className="card">
                            <div style={{ padding: '1rem 1.25rem', borderBottom: '1px solid var(--border)' }}>
                                <h3 style={{ fontSize: '0.95rem', fontWeight: 700, margin: 0 }}>Derniers appels</h3>
                            </div>
                            {(!recent_calls || recent_calls.length === 0) ? (
                                <div style={{ padding: '3rem 2rem', textAlign: 'center', color: 'var(--text-muted)' }}>Aucun appel</div>
                            ) : (
                                <div className="table-container">
                                    <table className="data-table">
                                        <thead><tr><th></th><th>Date</th><th>De</th><th>Vers</th><th>Statut</th><th style={{ textAlign: 'right' }}>Durée</th></tr></thead>
                                        <tbody>
                                            {recent_calls.map(c => {
                                                const st = CALL_STATUS[c.status] || { label: c.status, color: 'badge-gray' };
                                                return (
                                                    <tr key={c.id}>
                                                        <td style={{ width: 30 }}><CallDirectionIcon direction={c.direction} /></td>
                                                        <td style={{ fontSize: '0.8rem' }}>{formatDateTime(c.created_at)}</td>
                                                        <td style={{ fontFamily: 'ui-monospace, monospace', fontSize: '0.8rem' }}>{c.from_number || '-'}</td>
                                                        <td style={{ fontFamily: 'ui-monospace, monospace', fontSize: '0.8rem', color: 'var(--text-muted)' }}>{c.to_number || '-'}</td>
                                                        <td><div style={{ display: 'flex', alignItems: 'center', gap: '0.4rem' }}><CallStatusDot status={c.status} /><span style={{ fontSize: '0.8rem' }}>{st.label}</span></div></td>
                                                        <td style={{ textAlign: 'right', fontSize: '0.8rem', fontFeatureSettings: '"tnum"' }}>{formatDuration(c.duration)}</td>
                                                    </tr>
                                                );
                                            })}
                                        </tbody>
                                    </table>
                                </div>
                            )}
                        </div>
                    </>
                )}

                {tab === 'config' && (
                    <div className="card" style={{ padding: '1.5rem' }}>
                        <h3 style={{ margin: '0 0 1.25rem', fontSize: '1rem', fontWeight: 700 }}>Configuration de la ligne</h3>
                        <div className="form-group">
                            <label className="form-label">Libellé</label>
                            <input className="form-input" value={form.label} onChange={(e) => setForm({ ...form, label: e.target.value })} disabled={!editMode} placeholder="Nom interne (ex: Standard, Support, etc.)" />
                        </div>
                        <div className="form-group">
                            <label className="form-label">Description</label>
                            <textarea className="form-input" rows="3" value={form.description} onChange={(e) => setForm({ ...form, description: e.target.value })} disabled={!editMode} />
                        </div>
                        {(line.type === 'forward' || line.type === 'voicemail' || line.type === 'ivr') && (
                            <div className="form-group">
                                <label className="form-label">Numéro de redirection</label>
                                <input className="form-input" value={form.forward_number} onChange={(e) => setForm({ ...form, forward_number: e.target.value })} disabled={!editMode} placeholder="+41..." />
                            </div>
                        )}
                        {line.type === 'voicemail' && (
                            <div className="form-group">
                                <label className="form-label">Email pour les messages vocaux</label>
                                <input type="email" className="form-input" value={form.voicemail_email} onChange={(e) => setForm({ ...form, voicemail_email: e.target.value })} disabled={!editMode} />
                            </div>
                        )}
                        <div className="form-group">
                            <label className="form-label">Numéro de notification (SMS d'alerte)</label>
                            <input className="form-input" value={form.notification_number} onChange={(e) => setForm({ ...form, notification_number: e.target.value })} disabled={!editMode} placeholder="+41..." />
                        </div>
                        {(line.type === 'webhook' || line.type === 'external_api') && (
                            <div className="form-group">
                                <label className="form-label">URL du webhook</label>
                                <input className="form-input" value={form.webhook_url} onChange={(e) => setForm({ ...form, webhook_url: e.target.value })} disabled={!editMode} placeholder="https://..." />
                            </div>
                        )}
                        {line.type === 'link' && (
                            <>
                                <div className="form-group">
                                    <label className="form-label">URL à envoyer</label>
                                    <input className="form-input" value={form.link_url} onChange={(e) => setForm({ ...form, link_url: e.target.value })} disabled={!editMode} placeholder="https://..." />
                                </div>
                                <div className="form-group">
                                    <label className="form-label">Email destinataire (optionnel)</label>
                                    <input type="email" className="form-input" value={form.link_email} onChange={(e) => setForm({ ...form, link_email: e.target.value })} disabled={!editMode} />
                                </div>
                                <div className="form-group">
                                    <label className="form-label">Expéditeur SMS (max 11 caractères)</label>
                                    <input className="form-input" value={form.link_sms_sender} maxLength="11" onChange={(e) => setForm({ ...form, link_sms_sender: e.target.value })} disabled={!editMode} />
                                </div>
                            </>
                        )}
                        <div style={{ marginTop: '1.5rem', padding: '1rem 1.25rem', background: '#f8fafc', borderRadius: '0.75rem', border: '1px solid var(--border)' }}>
                            <h4 style={{ margin: '0 0 0.5rem', fontSize: '0.9rem', fontWeight: 700, color: 'var(--text)' }}>Enregistrement & transcription</h4>
                            <p style={{ margin: '0 0 1rem', fontSize: '0.8rem', color: 'var(--text-muted)' }}>
                                Activez l'enregistrement pour archiver les appels. La transcription par email envoie automatiquement le texte de chaque appel enregistré (Whisper, environ CHF 0.01/min facturé sur votre solde).
                            </p>
                            <label style={{ display: 'flex', alignItems: 'center', gap: '0.6rem', padding: '0.4rem 0', cursor: editMode ? 'pointer' : 'default' }}>
                                <input type="checkbox" checked={!!form.record_calls} onChange={(e) => setForm({ ...form, record_calls: e.target.checked })} disabled={!editMode} />
                                <span style={{ fontSize: '0.875rem' }}>Enregistrer les appels de cette ligne</span>
                            </label>
                            <label style={{ display: 'flex', alignItems: 'center', gap: '0.6rem', padding: '0.4rem 0', cursor: editMode ? 'pointer' : 'default' }}>
                                <input type="checkbox" checked={!!form.transcription_enabled} onChange={(e) => setForm({ ...form, transcription_enabled: e.target.checked })} disabled={!editMode || !form.record_calls} />
                                <span style={{ fontSize: '0.875rem' }}>Recevoir la transcription par email</span>
                            </label>
                            {form.transcription_enabled && (
                                <div style={{ marginTop: '0.75rem', display: 'grid', gridTemplateColumns: '2fr 1fr', gap: '0.75rem' }}>
                                    <div>
                                        <label className="form-label" style={{ fontSize: '0.75rem' }}>Email (laisser vide = email du compte)</label>
                                        <input type="email" className="form-input" value={form.transcription_email} onChange={(e) => setForm({ ...form, transcription_email: e.target.value })} disabled={!editMode} placeholder="vous@exemple.ch" />
                                    </div>
                                    <div>
                                        <label className="form-label" style={{ fontSize: '0.75rem' }}>Langue</label>
                                        <select className="form-input" value={form.transcription_language} onChange={(e) => setForm({ ...form, transcription_language: e.target.value })} disabled={!editMode}>
                                            <option value="fr">Français</option>
                                            <option value="en">English</option>
                                            <option value="de">Deutsch</option>
                                            <option value="it">Italiano</option>
                                            <option value="es">Español</option>
                                        </select>
                                    </div>
                                </div>
                            )}
                        </div>

                        {editMode && (
                            <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end', marginTop: '1rem' }}>
                                <button className="btn btn-secondary" onClick={() => { setEditMode(false); load(); }}>Annuler</button>
                                <button className="btn btn-primary" onClick={save} disabled={saving}>{saving ? 'Enregistrement…' : 'Enregistrer'}</button>
                            </div>
                        )}
                        <div style={{ marginTop: '1.5rem', padding: '1rem', background: '#f8fafc', borderRadius: '0.5rem', fontSize: '0.8rem', color: 'var(--text-muted)' }}>
                            ℹ️ Le numéro, le type de ligne et certains paramètres avancés ne peuvent être modifiés que par l'équipe Vocal. <a href="mailto:contact@vocal.ch" style={{ color: 'var(--primary)' }}>Nous contacter</a>.
                        </div>
                    </div>
                )}

                {tab === 'hours' && (
                    <BusinessHoursPanel form={form} setForm={setForm} editMode={editMode} saving={saving} onSave={save} onCancel={() => { setEditMode(false); load(); }} />
                )}

                {tab === 'dnd' && (
                    <DndPanel line={line} onChanged={load} />
                )}

                {tab === 'vacation' && (
                    <VacationPanel form={form} setForm={setForm} editMode={editMode} setEditMode={setEditMode} saving={saving} onSave={save} onCancel={() => { setEditMode(false); load(); }} />
                )}

                {tab === 'callback' && (
                    <CallbackPanel form={form} setForm={setForm} editMode={editMode} setEditMode={setEditMode} saving={saving} onSave={save} onCancel={() => { setEditMode(false); load(); }} />
                )}

                {tab === 'queue' && (
                    <LineAgentsPanel lineId={line.id} />
                )}

                {tab === 'bot' && (
                    <LineBotPanel line={line} form={form} setForm={setForm} editMode={editMode} saving={saving} onSave={save} onCancel={() => { setEditMode(false); load(); }} />
                )}

                {tab === 'routing' && (
                    <RoutingPanel lineId={line.id} />
                )}

                {tab === 'nps' && (
                    <NpsPanel line={line} onSaved={load} />
                )}

                {tab === 'subscription' && (
                    <SubscriptionCard line={line} subscription={subscription} onChanged={load} />
                )}

                {tab === 'widget' && (
                    <div className="card" style={{ padding: '1.5rem' }}>
                        <h3 style={{ margin: '0 0 0.75rem', fontSize: '1rem', fontWeight: 700 }}>Intégration Widget & API</h3>
                        <p style={{ margin: '0 0 1rem', color: 'var(--text-muted)', fontSize: '0.875rem' }}>
                            Pour intégrer cette ligne dans votre site web ou application, créez une clé API et ajoutez le script Vocal Widget.
                        </p>
                        <div style={{ background: '#f8fafc', padding: '1rem', borderRadius: '0.5rem', fontFamily: 'ui-monospace, monospace', fontSize: '0.8rem', overflow: 'auto', marginBottom: '1rem' }}>
                            <code>{`<script src="https://widget.vocal.ch/vocal-widget.js"\n    data-vocal-key="VOTRE_CLE_API"\n    data-vocal-line="${line.phone_number}"\n    async></script>`}</code>
                        </div>
                        <button className="btn btn-primary btn-sm" onClick={() => navigate('api-keys')}>
                            <Icons.Key className="w-4 h-4" /> Gérer mes clés API
                        </button>
                    </div>
                )}
            </div>
        </>
    );
};

// ==================== SUBSCRIPTION CARD (utilisée dans LineDetail) ====================
const SubscriptionCard = ({ line, subscription, onChanged }) => {
    const { notify } = useApp();
    const [busy, setBusy] = useState(false);
    const [period, setPeriod] = useState('monthly');

    const subscribe = async () => {
        setBusy(true);
        try {
            const r = await api.post('/my/billing/subscribe', { line_id: line.id, period });
            if (r?.error) { notify.error(r.error); return; }
            if (r.checkout_url) window.location.href = r.checkout_url;
        } catch (e) { notify.error(e.message); }
        finally { setBusy(false); }
    };

    const cancel = async () => {
        if (!confirm('Annuler cet abonnement à la fin de la période en cours ?')) return;
        setBusy(true);
        try {
            const r = await api.post(`/my/billing/subscriptions/${subscription.id}/cancel`);
            if (r?.error) notify.error(r.error);
            else { notify.success('Annulation programmée'); onChanged?.(); }
        } catch (e) { notify.error(e.message); }
        finally { setBusy(false); }
    };

    const reactivate = async () => {
        setBusy(true);
        try {
            const r = await api.post(`/my/billing/subscriptions/${subscription.id}/reactivate`);
            if (r?.error) notify.error(r.error);
            else { notify.success('Abonnement réactivé'); onChanged?.(); }
        } catch (e) { notify.error(e.message); }
        finally { setBusy(false); }
    };

    if (subscription && subscription.status !== 'canceled') {
        const isAnnual = subscription.billing_period === 'yearly';
        const isPastDue = subscription.status === 'past_due';
        return (
            <div className="card" style={{ padding: '1.5rem' }}>
                <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', flexWrap: 'wrap', gap: '1rem', marginBottom: '1rem' }}>
                    <div>
                        <h3 style={{ margin: '0 0 0.5rem', fontSize: '1.1rem', fontWeight: 700 }}>
                            Abonnement {isAnnual ? 'annuel' : 'mensuel'} actif
                        </h3>
                        <div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
                            <span className={`badge ${subscription.status === 'active' || subscription.status === 'trialing' ? 'badge-success' : 'badge-warning'}`}>
                                {subscription.status}
                            </span>
                            {subscription.cancel_at_period_end ? <span className="badge badge-warning">Annulation programmée</span> : null}
                            {isPastDue && <span className="badge badge-danger">Paiement échoué</span>}
                        </div>
                    </div>
                    <div style={{ textAlign: 'right' }}>
                        <div style={{ fontSize: '1.5rem', fontWeight: 800, color: 'var(--primary)' }}>{formatCurrency(subscription.amount, subscription.currency)}</div>
                        <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>par {isAnnual ? 'an' : 'mois'}</div>
                    </div>
                </div>
                <div style={{ background: '#f8fafc', padding: '1rem', borderRadius: '0.5rem', marginBottom: '1.25rem', fontSize: '0.85rem', color: 'var(--text-muted)' }}>
                    {subscription.current_period_end && (
                        <div>
                            {subscription.cancel_at_period_end
                                ? <>L'abonnement sera <strong style={{ color: 'var(--text-main)' }}>annulé le {formatDate(subscription.current_period_end)}</strong>.</>
                                : <>Prochain renouvellement automatique le <strong style={{ color: 'var(--text-main)' }}>{formatDate(subscription.current_period_end)}</strong>.</>}
                        </div>
                    )}
                    {subscription.last_payment_succeeded_at && (
                        <div style={{ marginTop: '0.4rem' }}>Dernier paiement réussi : {formatRelative(subscription.last_payment_succeeded_at)}</div>
                    )}
                </div>
                <div style={{ display: 'flex', gap: '0.5rem' }}>
                    {subscription.cancel_at_period_end ? (
                        <button className="btn btn-primary" onClick={reactivate} disabled={busy}>Réactiver l'abonnement</button>
                    ) : (
                        <button className="btn btn-secondary" onClick={cancel} disabled={busy}>Annuler</button>
                    )}
                </div>
            </div>
        );
    }

    return (
        <div className="card" style={{ padding: '1.5rem' }}>
            <h3 style={{ margin: '0 0 0.5rem', fontSize: '1.1rem', fontWeight: 700 }}>Souscrire un abonnement</h3>
            <p style={{ margin: '0 0 1.5rem', color: 'var(--text-muted)', fontSize: '0.9rem' }}>
                Activez votre numéro <strong style={{ color: 'var(--text-main)', fontFamily: 'ui-monospace, monospace' }}>{line.phone_number}</strong> avec un abonnement mensuel ou annuel.
            </p>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: '1rem', marginBottom: '1.5rem' }}>
                <button onClick={() => setPeriod('monthly')}
                    style={{ background: period === 'monthly' ? '#eef2ff' : '#fff', border: `2px solid ${period === 'monthly' ? 'var(--primary)' : 'var(--border)'}`, borderRadius: '0.75rem', padding: '1.25rem', cursor: 'pointer', textAlign: 'left' }}>
                    <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)', textTransform: 'uppercase', fontWeight: 600 }}>Mensuel</div>
                    <div style={{ fontSize: '1.75rem', fontWeight: 800, color: 'var(--text-main)', margin: '0.25rem 0' }}>9.90 CHF<span style={{ fontSize: '0.8rem', fontWeight: 500, color: 'var(--text-muted)' }}>/mois</span></div>
                    <div style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>Sans engagement</div>
                </button>
                <button onClick={() => setPeriod('yearly')}
                    style={{ background: period === 'yearly' ? '#eef2ff' : '#fff', border: `2px solid ${period === 'yearly' ? 'var(--primary)' : 'var(--border)'}`, borderRadius: '0.75rem', padding: '1.25rem', cursor: 'pointer', position: 'relative', textAlign: 'left' }}>
                    <span style={{ position: 'absolute', top: 8, right: 8, background: 'var(--primary)', color: '#fff', fontSize: '0.65rem', fontWeight: 700, padding: '0.2rem 0.5rem', borderRadius: '999px' }}>-40%</span>
                    <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)', textTransform: 'uppercase', fontWeight: 600 }}>Annuel</div>
                    <div style={{ fontSize: '1.75rem', fontWeight: 800, color: 'var(--text-main)', margin: '0.25rem 0' }}>5.90 CHF<span style={{ fontSize: '0.8rem', fontWeight: 500, color: 'var(--text-muted)' }}>/mois</span></div>
                    <div style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>70.80 CHF facturés une fois par an</div>
                </button>
            </div>
            <button className="btn btn-primary" onClick={subscribe} disabled={busy} style={{ width: '100%' }}>
                {busy ? 'Redirection vers Stripe…' : `S'abonner (${period === 'yearly' ? '70.80 CHF/an' : '9.90 CHF/mois'})`}
            </button>
            <p style={{ marginTop: '0.75rem', fontSize: '0.75rem', color: 'var(--text-muted)', textAlign: 'center' }}>
                Paiement sécurisé par Stripe • annulable à tout moment depuis votre espace.
            </p>
        </div>
    );
};

// ==================== BUSINESS HOURS PANEL ====================
const BusinessHoursPanel = ({ form, setForm, editMode, saving, onSave, onCancel }) => {
    const hours = form.business_hours || defaultBusinessHours();
    const setDay = (dayId, patch) => {
        const next = { ...hours, [dayId]: { ...(hours[dayId] || { open: false, from: '09:00', to: '18:00' }), ...patch } };
        setForm(f => ({ ...f, business_hours: next }));
    };
    const setHolidays = (val) => {
        const list = val.split('\n').map(s => s.trim()).filter(Boolean);
        setForm(f => ({ ...f, business_hours: { ...hours, holidays: list } }));
    };

    return (
        <div className="grid-cols-1" style={{ display: 'grid', gap: '1rem' }}>
            <div className="card-flat">
                <div className="card-flat-header">
                    <Icons.Calendar className="w-5 h-5" />
                    <h2>Heures d'ouverture</h2>
                </div>
                <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
                    <label className="toggle-row">
                        <input
                            type="checkbox"
                            disabled={!editMode}
                            checked={!!form.business_hours_enabled}
                            onChange={e => setForm(f => ({ ...f, business_hours_enabled: e.target.checked }))}
                        />
                        <span>Activer le routage horaire (hors plage = action ci-dessous)</span>
                    </label>

                    <div className="form-row">
                        <label>Fuseau horaire</label>
                        <input
                            type="text"
                            value={form.timezone || 'Europe/Zurich'}
                            disabled={!editMode}
                            onChange={e => setForm(f => ({ ...f, timezone: e.target.value }))}
                            placeholder="Europe/Zurich"
                        />
                    </div>

                    <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                        {DAY_LABELS.map(d => {
                            const day = hours[d.id] || { open: false, from: '09:00', to: '18:00' };
                            return (
                                <div key={d.id} style={{ display: 'grid', gridTemplateColumns: '1.5rem 6rem 1fr 1fr', gap: '0.5rem', alignItems: 'center' }}>
                                    <input
                                        type="checkbox"
                                        disabled={!editMode}
                                        checked={!!day.open}
                                        onChange={e => setDay(d.id, { open: e.target.checked })}
                                    />
                                    <span style={{ fontWeight: 600 }}>{d.label}</span>
                                    <input
                                        type="time"
                                        disabled={!editMode || !day.open}
                                        value={day.from || '09:00'}
                                        onChange={e => setDay(d.id, { from: e.target.value })}
                                    />
                                    <input
                                        type="time"
                                        disabled={!editMode || !day.open}
                                        value={day.to || '18:00'}
                                        onChange={e => setDay(d.id, { to: e.target.value })}
                                    />
                                </div>
                            );
                        })}
                    </div>

                    <div className="form-row">
                        <label>Jours fériés (1 par ligne, format YYYY-MM-DD)</label>
                        <textarea
                            rows={4}
                            disabled={!editMode}
                            value={(hours.holidays || []).join('\n')}
                            onChange={e => setHolidays(e.target.value)}
                            placeholder="2026-01-01&#10;2026-12-25"
                        />
                    </div>
                </div>
            </div>

            <div className="card-flat">
                <div className="card-flat-header">
                    <Icons.Settings className="w-5 h-5" />
                    <h2>Hors heures d'ouverture</h2>
                </div>
                <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
                    <div className="form-row">
                        <label>Action</label>
                        <select
                            value={form.out_of_hours_action || 'message'}
                            disabled={!editMode}
                            onChange={e => setForm(f => ({ ...f, out_of_hours_action: e.target.value }))}
                        >
                            <option value="message">Lire un message puis raccrocher</option>
                            <option value="voicemail">Lire un message puis prendre un message vocal</option>
                            <option value="forward">Transférer vers un autre numéro</option>
                            <option value="hangup">Raccrocher immédiatement</option>
                        </select>
                    </div>

                    {(form.out_of_hours_action === 'forward') && (
                        <div className="form-row">
                            <label>Numéro de transfert hors heures</label>
                            <input
                                type="text"
                                value={form.out_of_hours_forward_number || ''}
                                disabled={!editMode}
                                onChange={e => setForm(f => ({ ...f, out_of_hours_forward_number: e.target.value }))}
                                placeholder="+41 79 ..."
                            />
                        </div>
                    )}

                    {(form.out_of_hours_action === 'message' || form.out_of_hours_action === 'voicemail') && (
                        <div className="form-row">
                            <label>Message à diffuser</label>
                            <textarea
                                rows={3}
                                disabled={!editMode}
                                value={form.out_of_hours_message || ''}
                                onChange={e => setForm(f => ({ ...f, out_of_hours_message: e.target.value }))}
                                placeholder="Nos bureaux sont actuellement fermés. Merci de rappeler aux heures d'ouverture."
                            />
                        </div>
                    )}
                </div>
            </div>

            {editMode && (
                <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end' }}>
                    <button className="btn btn-secondary" onClick={onCancel} disabled={saving}>Annuler</button>
                    <button className="btn btn-primary" onClick={onSave} disabled={saving}>
                        {saving ? 'Enregistrement…' : 'Enregistrer'}
                    </button>
                </div>
            )}
        </div>
    );
};

// ==================== LINE BOT PANEL ====================
const LineBotPanel = ({ line, form, setForm, editMode, saving, onSave, onCancel }) => {
    const { notify, navigate } = useApp();
    const [bots, setBots] = useState([]);
    const [loading, setLoading] = useState(true);
    useEffect(() => {
        (async () => {
            try { const r = await api.get('/my/bots'); setBots(r?.bots || []); }
            catch (e) {} finally { setLoading(false); }
        })();
    }, []);

    const selected = bots.find(b => b.id === form.voice_bot_id);

    return (
        <div className="grid-cols-1" style={{ display: 'grid', gap: '1rem' }}>
            <div className="card-flat">
                <div className="card-flat-header">
                    <Icons.Robot className="w-5 h-5" />
                    <h2>Bot vocal sur cette ligne</h2>
                </div>
                <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
                    {loading ? (
                        <p style={{ color: 'var(--text-muted)' }}>Chargement…</p>
                    ) : bots.length === 0 ? (
                        <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                            <p style={{ color: 'var(--text-muted)', margin: 0 }}>
                                Aucun bot vocal créé pour le moment.
                            </p>
                            <button className="btn btn-primary btn-sm" style={{ alignSelf: 'flex-start' }}
                                onClick={() => navigate('bots')}>
                                <Icons.Plus className="w-4 h-4" /> Créer un bot
                            </button>
                        </div>
                    ) : (
                        <>
                            <div className="form-row">
                                <label>Bot associé</label>
                                <select
                                    value={form.voice_bot_id || ''}
                                    disabled={!editMode}
                                    onChange={e => setForm(f => ({ ...f, voice_bot_id: e.target.value ? Number(e.target.value) : null }))}
                                >
                                    <option value="">- Aucun (mode standard) -</option>
                                    {bots.map(b => (
                                        <option key={b.id} value={b.id}>{b.name}{b.is_active ? '' : ' (inactif)'}</option>
                                    ))}
                                </select>
                            </div>
                            {selected && (
                                <div style={{ padding: '0.75rem', background: 'var(--bg-soft)', borderRadius: '0.5rem', fontSize: '0.875rem', display: 'flex', flexDirection: 'column', gap: '0.25rem' }}>
                                    <div><strong>{selected.name}</strong></div>
                                    {selected.description && <div style={{ color: 'var(--text-muted)' }}>{selected.description}</div>}
                                    <div style={{ color: 'var(--text-muted)', fontSize: '0.75rem' }}>
                                        Voix: {selected.voice} · Langue: {selected.language} · {selected.is_active ? 'Actif' : 'Inactif'}
                                    </div>
                                    <button className="btn btn-secondary btn-sm" style={{ alignSelf: 'flex-start', marginTop: '0.5rem' }}
                                        onClick={() => navigate('bots', { botId: selected.id })}>
                                        Configurer ce bot
                                    </button>
                                </div>
                            )}
                            <p style={{ fontSize: '0.75rem', color: 'var(--text-muted)', margin: 0 }}>
                                Quand un bot est associé, les appels entrants sur cette ligne sont pris en charge automatiquement par l'IA. Les enregistrements et transcriptions restent disponibles.
                            </p>
                        </>
                    )}
                </div>
            </div>

            {editMode && (
                <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end' }}>
                    <button className="btn btn-secondary" onClick={onCancel} disabled={saving}>Annuler</button>
                    <button className="btn btn-primary" onClick={onSave} disabled={saving}>
                        {saving ? 'Enregistrement…' : 'Enregistrer'}
                    </button>
                </div>
            )}
        </div>
    );
};

// ==================== DND PANEL ====================
const DndPanel = ({ line, onChanged }) => {
    const { notify } = useApp();
    const [busy, setBusy] = useState(false);
    const isActive = line.dnd_until && new Date(line.dnd_until).getTime() > Date.now();
    const enableFor = async (minutes, message) => {
        setBusy(true);
        try {
            await api.post(`/my/lines/${line.id}/dnd`, { duration_minutes: minutes, message: message || line.dnd_message });
            notify.success(`Ne pas déranger activé pour ${minutes < 60 ? minutes + ' min' : Math.round(minutes / 60) + 'h'}`);
            onChanged && onChanged();
        } catch (e) { notify.error('Erreur'); } finally { setBusy(false); }
    };
    const disable = async () => {
        setBusy(true);
        try {
            await api.post(`/my/lines/${line.id}/dnd`, { until: null });
            notify.success('Ne pas déranger désactivé');
            onChanged && onChanged();
        } catch (e) { notify.error('Erreur'); } finally { setBusy(false); }
    };
    return (
        <div className="card-flat">
            <div className="card-flat-header">
                <Icons.Moon className="w-5 h-5" />
                <h2>Mode "Ne pas déranger"</h2>
            </div>
            <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
                {isActive ? (
                    <div style={{ padding: '0.75rem 1rem', background: '#fef3c7', border: '1px solid #fcd34d', borderRadius: '0.5rem', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                        <div>
                            <div style={{ fontWeight: 600, color: '#854d0e' }}>Actuellement actif</div>
                            <div style={{ fontSize: '0.8rem', color: '#92400e' }}>Jusqu'à {new Date(line.dnd_until).toLocaleString('fr-CH')}</div>
                        </div>
                        <button className="btn btn-secondary btn-sm" onClick={disable} disabled={busy}>Désactiver</button>
                    </div>
                ) : (
                    <p style={{ color: 'var(--text-muted)', margin: 0 }}>
                        Bloque temporairement les appels entrants. Les appelants entendent un message court (configurable ci-dessous) et l'appel est terminé proprement. Si "Rappel auto" est aussi activé, les appelants seront rappelés automatiquement à la fin de la période.
                    </p>
                )}
                <div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
                    <button className="btn btn-primary btn-sm" onClick={() => enableFor(30)} disabled={busy}>30 min</button>
                    <button className="btn btn-primary btn-sm" onClick={() => enableFor(60)} disabled={busy}>1 h</button>
                    <button className="btn btn-primary btn-sm" onClick={() => enableFor(120)} disabled={busy}>2 h</button>
                    <button className="btn btn-primary btn-sm" onClick={() => enableFor(240)} disabled={busy}>4 h</button>
                    <button className="btn btn-primary btn-sm" onClick={() => {
                        const tomorrow = new Date(); tomorrow.setHours(8, 0, 0, 0);
                        if (tomorrow.getTime() < Date.now()) tomorrow.setDate(tomorrow.getDate() + 1);
                        const mins = Math.round((tomorrow.getTime() - Date.now()) / 60000);
                        enableFor(mins);
                    }} disabled={busy}>Jusqu'à demain 8h</button>
                </div>
                <div className="form-row">
                    <label>Message lu pendant le DND (optionnel)</label>
                    <input className="form-input" defaultValue={line.dnd_message || ''} placeholder="Je suis indisponible pour le moment, merci de rappeler plus tard."
                        onBlur={async (e) => {
                            try { await api.put(`/my/lines/${line.id}`, { dnd_message: e.target.value || null }); } catch (err) {}
                        }} />
                </div>
            </div>
        </div>
    );
};

// ==================== VACATION PANEL ====================
const VacationPanel = ({ form, setForm, editMode, setEditMode, saving, onSave, onCancel }) => {
    const update = (fn) => {
        if (!editMode && setEditMode) setEditMode(true);
        setForm(fn);
    };
    return (
        <div className="card-flat">
            <div className="card-flat-header">
                <Icons.Briefcase className="w-5 h-5" />
                <h2>Mode Vacances</h2>
            </div>
            <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
                <p style={{ color: 'var(--text-muted)', margin: 0, fontSize: '0.875rem' }}>
                    Pendant les vacances, les appelants entendent votre message et peuvent laisser un message vocal qui sera transmis par email. La transcription IA est conservée si activée.
                </p>
                <label className="toggle-row">
                    <input type="checkbox" checked={!!form.vacation_enabled}
                        onChange={e => update(f => ({ ...f, vacation_enabled: e.target.checked }))} />
                    <span>Activer le mode vacances</span>
                </label>
                {form.vacation_enabled && (
                    <>
                        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem' }}>
                            <div className="form-row">
                                <label>Du</label>
                                <input type="datetime-local" className="form-input" value={form.vacation_from || ''}
                                    onChange={e => update(f => ({ ...f, vacation_from: e.target.value }))} />
                            </div>
                            <div className="form-row">
                                <label>Au</label>
                                <input type="datetime-local" className="form-input" value={form.vacation_to || ''}
                                    onChange={e => update(f => ({ ...f, vacation_to: e.target.value }))} />
                            </div>
                        </div>
                        <div className="form-row">
                            <label>Message lu aux appelants</label>
                            <textarea className="form-input" rows={3} value={form.vacation_message || ''}
                                placeholder="Nous sommes en congés du X au Y. Vous pouvez laisser un message après le bip ou nous écrire à contact@…"
                                onChange={e => update(f => ({ ...f, vacation_message: e.target.value }))} />
                        </div>
                        <div className="form-row">
                            <label>Email pour transmission des messages vocaux (optionnel)</label>
                            <input type="email" className="form-input" value={form.vacation_forward_email || ''}
                                placeholder="vous@exemple.ch"
                                onChange={e => update(f => ({ ...f, vacation_forward_email: e.target.value }))} />
                        </div>
                    </>
                )}
                {editMode && (
                    <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end' }}>
                        <button className="btn btn-secondary" onClick={onCancel} disabled={saving}>Annuler</button>
                        <button className="btn btn-primary" onClick={onSave} disabled={saving}>{saving ? 'Enregistrement…' : 'Enregistrer'}</button>
                    </div>
                )}
            </div>
        </div>
    );
};

// ==================== CALLBACK PANEL ====================
const CallbackPanel = ({ form, setForm, editMode, setEditMode, saving, onSave, onCancel }) => {
    const update = (fn) => {
        if (!editMode && setEditMode) setEditMode(true);
        setForm(fn);
    };
    return (
        <div className="card-flat">
            <div className="card-flat-header">
                <Icons.Refresh className="w-5 h-5" />
                <h2>Rappel automatique des appels manqués</h2>
            </div>
            <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
                <p style={{ color: 'var(--text-muted)', margin: 0, fontSize: '0.875rem' }}>
                    Quand un appel n'est pas pris (hors horaires, DND, file d'attente vide), Vocal rappelle automatiquement l'appelant après un délai. Pratique pour ne perdre aucun lead.
                </p>
                <label className="toggle-row">
                    <input type="checkbox" checked={!!form.callback_enabled}
                        onChange={e => update(f => ({ ...f, callback_enabled: e.target.checked }))} />
                    <span>Activer le rappel automatique</span>
                </label>
                {form.callback_enabled && (
                    <>
                        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem' }}>
                            <div className="form-row">
                                <label>Délai avant rappel (secondes)</label>
                                <input type="number" min="15" max="3600" className="form-input"
                                    value={form.callback_delay_seconds ?? 60}
                                    onChange={e => update(f => ({ ...f, callback_delay_seconds: parseInt(e.target.value) || 60 }))} />
                            </div>
                            <div className="form-row">
                                <label>Tentatives max</label>
                                <input type="number" min="1" max="5" className="form-input"
                                    value={form.callback_max_attempts ?? 1}
                                    onChange={e => update(f => ({ ...f, callback_max_attempts: parseInt(e.target.value) || 1 }))} />
                            </div>
                        </div>
                        <div className="form-row">
                            <label>Message lu en début de rappel</label>
                            <textarea className="form-input" rows={2} value={form.callback_message || ''}
                                placeholder="Bonjour, vous nous avez appelé tout à l'heure, nous vous rappelons. Merci de patienter…"
                                onChange={e => update(f => ({ ...f, callback_message: e.target.value }))} />
                        </div>
                    </>
                )}
                {editMode && (
                    <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end' }}>
                        <button className="btn btn-secondary" onClick={onCancel} disabled={saving}>Annuler</button>
                        <button className="btn btn-primary" onClick={onSave} disabled={saving}>{saving ? 'Enregistrement…' : 'Enregistrer'}</button>
                    </div>
                )}
            </div>
        </div>
    );
};

// ==================== LINE AGENTS PANEL (queue) ====================
const LineAgentsPanel = ({ lineId }) => {
    const { notify } = useApp();
    const [agents, setAgents] = useState([]);
    const [loading, setLoading] = useState(true);
    const [show, setShow] = useState(false);
    const [draft, setDraft] = useState({ label: '', agent_type: 'number', target: '', priority: 0, timeout_seconds: 25 });
    const load = useCallback(async () => {
        setLoading(true);
        try { const r = await api.get(`/my/lines/${lineId}/agents`); setAgents(r?.agents || []); }
        catch (e) { notify.error('Erreur chargement agents'); } finally { setLoading(false); }
    }, [lineId, notify]);
    useEffect(() => { load(); }, [load]);
    const create = async () => {
        if (!draft.target.trim()) return notify.error('Indiquez un numéro / identité');
        try {
            const r = await api.post(`/my/lines/${lineId}/agents`, draft);
            if (r?.error) return notify.error(r.error);
            notify.success('Agent ajouté'); setShow(false);
            setDraft({ label: '', agent_type: 'number', target: '', priority: 0, timeout_seconds: 25 });
            load();
        } catch (e) { notify.error('Erreur: ' + e.message); }
    };
    const update = async (a, patch) => {
        try { await api.put(`/my/lines/${lineId}/agents/${a.id}`, patch); load(); }
        catch (e) { notify.error('Erreur'); }
    };
    const remove = async (a) => {
        if (!confirm(`Supprimer l'agent ${a.label || a.target} ?`)) return;
        try { await api.del(`/my/lines/${lineId}/agents/${a.id}`); load(); }
        catch (e) { notify.error('Erreur'); }
    };
    return (
        <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
            <div className="card-flat">
                <div className="card-flat-header">
                    <Icons.Users className="w-5 h-5" />
                    <h2>Agents du standard</h2>
                    <button className="btn btn-primary btn-sm" style={{ marginLeft: 'auto' }} onClick={() => setShow(true)}>
                        <Icons.Plus className="w-4 h-4" /> Ajouter
                    </button>
                </div>
                <div className="card-flat-content">
                    {loading ? <p>Chargement…</p> : agents.length === 0 ? (
                        <p style={{ color: 'var(--text-muted)' }}>Aucun agent. Ajoutez les téléphones de votre équipe pour qu'ils sonnent en parallèle ou en cascade.</p>
                    ) : (
                        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.875rem' }}>
                            <thead><tr style={{ textAlign: 'left', color: 'var(--text-muted)', fontSize: '0.75rem' }}>
                                <th style={{ padding: '0.5rem 0' }}>Nom</th><th>Type</th><th>Cible</th><th>Priorité</th><th>Timeout</th><th>Actif</th><th></th>
                            </tr></thead>
                            <tbody>
                                {agents.map(a => (
                                    <tr key={a.id} style={{ borderTop: '1px solid var(--border)' }}>
                                        <td style={{ padding: '0.5rem 0' }}>{a.label || '-'}</td>
                                        <td>{a.agent_type}</td>
                                        <td style={{ fontFamily: 'ui-monospace, monospace' }}>{a.target}</td>
                                        <td>{a.priority === 0 ? 'parallèle' : `seq #${a.priority}`}</td>
                                        <td>{a.timeout_seconds}s</td>
                                        <td><input type="checkbox" checked={!!a.is_active} onChange={e => update(a, { is_active: e.target.checked })} /></td>
                                        <td><button className="btn btn-secondary btn-sm" onClick={() => remove(a)}><Icons.Trash className="w-4 h-4" /></button></td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    )}
                </div>
            </div>
            {show && (
                <div className="card" style={{ padding: '1rem', border: '2px solid var(--primary-light)' }}>
                    <h3 style={{ margin: '0 0 0.75rem' }}>Nouvel agent</h3>
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem' }}>
                        <div className="form-row">
                            <label>Nom (Anna, Pierre…)</label>
                            <input className="form-input" value={draft.label} onChange={e => setDraft({ ...draft, label: e.target.value })} />
                        </div>
                        <div className="form-row">
                            <label>Type</label>
                            <select className="form-input" value={draft.agent_type} onChange={e => setDraft({ ...draft, agent_type: e.target.value })}>
                                <option value="number">Numéro de téléphone</option>
                                <option value="client">Client VoIP (app Vocal)</option>
                                <option value="sip">SIP URI</option>
                            </select>
                        </div>
                        <div className="form-row">
                            <label>Cible</label>
                            <input className="form-input" value={draft.target} onChange={e => setDraft({ ...draft, target: e.target.value })}
                                placeholder={draft.agent_type === 'number' ? '+41791234567' : draft.agent_type === 'client' ? 'identifier-vocal' : 'sip:user@host'} />
                        </div>
                        <div className="form-row">
                            <label>Priorité (0 = parallèle, &gt;0 = ordre séquentiel)</label>
                            <input type="number" className="form-input" value={draft.priority} onChange={e => setDraft({ ...draft, priority: parseInt(e.target.value) || 0 })} />
                        </div>
                        <div className="form-row">
                            <label>Timeout (s)</label>
                            <input type="number" className="form-input" value={draft.timeout_seconds} onChange={e => setDraft({ ...draft, timeout_seconds: parseInt(e.target.value) || 25 })} />
                        </div>
                    </div>
                    <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end', marginTop: '0.75rem' }}>
                        <button className="btn btn-secondary" onClick={() => setShow(false)}>Annuler</button>
                        <button className="btn btn-primary" onClick={create}>Ajouter</button>
                    </div>
                </div>
            )}
        </div>
    );
};

// ==================== BOTS VIEW ====================
const VOICES = [
    { id: 'alloy',   label: 'Alloy (neutre)' },
    { id: 'echo',    label: 'Echo (homme)' },
    { id: 'fable',   label: 'Fable (homme doux)' },
    { id: 'onyx',    label: 'Onyx (homme grave)' },
    { id: 'nova',    label: 'Nova (femme)' },
    { id: 'shimmer', label: 'Shimmer (femme douce)' },
];
const LANGS = [
    { id: 'fr', label: 'Français' },
    { id: 'en', label: 'Anglais' },
    { id: 'de', label: 'Allemand' },
    { id: 'it', label: 'Italien' },
    { id: 'es', label: 'Espagnol' },
];

const BotsView = () => {
    const { notify, selectedBotId, setSelectedBotId } = useApp();
    const [bots, setBots] = useState([]);
    const [loading, setLoading] = useState(true);
    const [creating, setCreating] = useState(false);
    const [newName, setNewName] = useState('');

    const load = useCallback(async () => {
        try { const r = await api.get('/my/bots'); setBots(r?.bots || []); }
        catch (e) { notify.error('Erreur chargement'); }
        finally { setLoading(false); }
    }, []);
    useEffect(() => { load(); }, [load]);

    const create = async () => {
        if (!newName.trim()) { notify.error('Nom requis'); return; }
        setCreating(true);
        try {
            const r = await api.post('/my/bots', { name: newName.trim() });
            if (r?.error) notify.error(r.error);
            else { notify.success('Bot créé'); setNewName(''); setSelectedBotId(r.bot?.id || null); load(); }
        } catch (e) { notify.error('Erreur'); }
        finally { setCreating(false); }
    };

    if (selectedBotId) {
        return <BotDetailView botId={selectedBotId} onBack={() => { setSelectedBotId(null); load(); }} />;
    }

    return (
        <div className="page-container">
            <div className="page-header">
                <h1><Icons.Robot className="w-6 h-6" /> Bots vocaux</h1>
                <p style={{ color: 'var(--text-muted)' }}>Créez un assistant IA capable de répondre à vos appels, d'apprendre de vos sites et de progresser à chaque conversation.</p>
            </div>

            <div className="card-flat" style={{ marginBottom: '1rem' }}>
                <div className="card-flat-header">
                    <Icons.Plus className="w-5 h-5" />
                    <h2>Nouveau bot</h2>
                </div>
                <div className="card-flat-content" style={{ display: 'flex', gap: '0.5rem' }}>
                    <input type="text" placeholder="Nom du bot (ex: Assistant standard)" value={newName} onChange={e => setNewName(e.target.value)} style={{ flex: 1 }} />
                    <button className="btn btn-primary" onClick={create} disabled={creating}>{creating ? 'Création…' : 'Créer'}</button>
                </div>
            </div>

            <div className="card-flat">
                <div className="card-flat-header">
                    <Icons.Robot className="w-5 h-5" />
                    <h2>Mes bots</h2>
                </div>
                <div className="card-flat-content">
                    {loading ? (
                        <p style={{ color: 'var(--text-muted)' }}>Chargement…</p>
                    ) : bots.length === 0 ? (
                        <p style={{ color: 'var(--text-muted)' }}>Aucun bot pour le moment. Créez-en un ci-dessus.</p>
                    ) : (
                        <div style={{ display: 'grid', gap: '0.5rem', gridTemplateColumns: 'repeat(auto-fill, minmax(260px, 1fr))' }}>
                            {bots.map(b => (
                                <button key={b.id} onClick={() => setSelectedBotId(b.id)} className="card" style={{ textAlign: 'left', cursor: 'pointer', padding: '1rem' }}>
                                    <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', marginBottom: '0.4rem' }}>
                                        <Icons.Robot className="w-5 h-5" />
                                        <strong>{b.name}</strong>
                                        {!b.is_active && <span className="badge badge-gray">inactif</span>}
                                    </div>
                                    {b.description && <div style={{ fontSize: '0.8rem', color: 'var(--text-muted)', marginBottom: '0.4rem' }}>{b.description}</div>}
                                    <div style={{ fontSize: '0.7rem', color: 'var(--text-muted)' }}>
                                        Voix: {b.voice} · {b.language?.toUpperCase()}
                                    </div>
                                </button>
                            ))}
                        </div>
                    )}
                </div>
            </div>
        </div>
    );
};

const BotDetailView = ({ botId, onBack }) => {
    const { notify } = useApp();
    const [bot, setBot] = useState(null);
    const [loading, setLoading] = useState(true);
    const [tab, setTab] = useState('config');
    const [editMode, setEditMode] = useState(false);
    const [saving, setSaving] = useState(false);
    const [form, setForm] = useState({});

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const r = await api.get(`/my/bots/${botId}`);
            if (r?.error) { notify.error(r.error); return; }
            setBot(r.bot);
            setForm({
                name: r.bot.name || '',
                description: r.bot.description || '',
                instructions: r.bot.instructions || '',
                voice: r.bot.voice || 'alloy',
                language: r.bot.language || 'fr',
                greeting: r.bot.greeting || '',
                human_transfer_number: r.bot.human_transfer_number || '',
                learn_from_calls: !!r.bot.learn_from_calls,
                max_call_duration: r.bot.max_call_duration || 600,
                is_active: !!r.bot.is_active,
                appointments_enabled: !!r.bot.appointments_enabled,
                appointment_duration_minutes: r.bot.appointment_duration_minutes || 30,
                appointment_buffer_minutes: r.bot.appointment_buffer_minutes || 0,
                appointment_business_hours: r.bot.appointment_business_hours || '',
                appointment_notify_email: r.bot.appointment_notify_email || '',
                appointment_max_days_ahead: r.bot.appointment_max_days_ahead || 30,
                lead_scoring_enabled: !!r.bot.lead_scoring_enabled,
                lead_scoring_prompt: r.bot.lead_scoring_prompt || '',
                custom_voice_provider: r.bot.custom_voice_provider || '',
                custom_voice_id: r.bot.custom_voice_id || '',
            });
        } catch (e) { notify.error('Erreur'); }
        finally { setLoading(false); }
    }, [botId]);
    useEffect(() => { load(); }, [load]);

    const save = async () => {
        setSaving(true);
        try {
            const r = await api.put(`/my/bots/${botId}`, form);
            if (r?.error) notify.error(r.error);
            else { notify.success('Bot mis à jour'); setEditMode(false); load(); }
        } catch (e) { notify.error('Erreur'); }
        finally { setSaving(false); }
    };

    const remove = async () => {
        if (!confirm('Supprimer ce bot ?')) return;
        try {
            const r = await api.del(`/my/bots/${botId}`);
            if (r?.error) notify.error(r.error);
            else { notify.success('Bot supprimé'); onBack(); }
        } catch (e) { notify.error('Erreur'); }
    };

    if (loading) return <div className="page-container"><p>Chargement…</p></div>;
    if (!bot) return <div className="page-container"><p>Bot introuvable</p></div>;

    return (
        <div className="page-container">
            <div className="page-header" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                <div>
                    <button className="btn btn-secondary btn-sm" onClick={onBack} style={{ marginBottom: '0.5rem' }}>
                        <Icons.ChevronLeft className="w-4 h-4" /> Retour
                    </button>
                    <h1><Icons.Robot className="w-6 h-6" /> {bot.name}</h1>
                </div>
                <div className="page-actions" style={{ display: 'flex', gap: '0.5rem' }}>
                    {tab === 'config' && !editMode && (
                        <button className="btn btn-primary btn-sm" onClick={() => setEditMode(true)}>
                            <Icons.Edit className="w-4 h-4" /> Modifier
                        </button>
                    )}
                    <button className="btn btn-secondary btn-sm" onClick={remove} style={{ color: 'var(--danger)' }}>
                        <Icons.Trash className="w-4 h-4" /> Supprimer
                    </button>
                </div>
            </div>

            <div className="tabs" style={{ display: 'flex', gap: '0.25rem', borderBottom: '1px solid var(--border)', marginBottom: '1rem', overflowX: 'auto' }}>
                {[
                    { id: 'config', label: 'Configuration', icon: Icons.Settings },
                    { id: 'sources', label: 'Sources', icon: Icons.Globe },
                    { id: 'knowledge', label: 'Connaissances', icon: Icons.Document },
                    { id: 'learnings', label: 'Apprentissages', icon: Icons.Sparkles },
                    { id: 'conversations', label: 'Conversations', icon: Icons.Phone },
                    { id: 'appointments', label: 'Rendez-vous', icon: Icons.Calendar },
                    { id: 'leads', label: 'Lead scoring', icon: Icons.AlertCircle },
                    { id: 'voice', label: 'Voix', icon: Icons.Sparkles },
                ].map(t => (
                    <button key={t.id}
                        onClick={() => { setTab(t.id); if (editMode) { setEditMode(false); load(); } }}
                        className={`tab ${tab === t.id ? 'active' : ''}`}
                        style={{ padding: '0.5rem 0.75rem', border: 'none', background: 'transparent', borderBottom: tab === t.id ? '2px solid var(--primary)' : '2px solid transparent', color: tab === t.id ? 'var(--primary)' : 'var(--text-muted)', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '0.4rem', fontWeight: 500 }}>
                        <t.icon className="w-4 h-4" /> {t.label}
                    </button>
                ))}
            </div>

            {tab === 'config' && (
                <div className="card-flat">
                    <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
                        <div className="form-row"><label>Nom</label>
                            <input type="text" disabled={!editMode} value={form.name} onChange={e => setForm(f => ({ ...f, name: e.target.value }))} />
                        </div>
                        <div className="form-row"><label>Description</label>
                            <input type="text" disabled={!editMode} value={form.description} onChange={e => setForm(f => ({ ...f, description: e.target.value }))} />
                        </div>
                        <div className="form-row"><label>Voix</label>
                            <select disabled={!editMode} value={form.voice} onChange={e => setForm(f => ({ ...f, voice: e.target.value }))}>
                                {VOICES.map(v => <option key={v.id} value={v.id}>{v.label}</option>)}
                            </select>
                        </div>
                        <div className="form-row"><label>Langue</label>
                            <select disabled={!editMode} value={form.language} onChange={e => setForm(f => ({ ...f, language: e.target.value }))}>
                                {LANGS.map(l => <option key={l.id} value={l.id}>{l.label}</option>)}
                            </select>
                        </div>
                        <div className="form-row"><label>Message d'accueil</label>
                            <textarea rows={2} disabled={!editMode} value={form.greeting} onChange={e => setForm(f => ({ ...f, greeting: e.target.value }))} />
                        </div>
                        <div className="form-row"><label>Instructions / personnalité</label>
                            <textarea rows={5} disabled={!editMode} value={form.instructions} onChange={e => setForm(f => ({ ...f, instructions: e.target.value }))}
                                placeholder="Tu es un assistant pour [entreprise]. Tu es professionnel, concis. Si tu ne sais pas, tu proposes de transférer à un humain." />
                        </div>
                        <div className="form-row"><label>Numéro de transfert humain</label>
                            <input type="text" disabled={!editMode} value={form.human_transfer_number} onChange={e => setForm(f => ({ ...f, human_transfer_number: e.target.value }))} placeholder="+41 79 ..." />
                        </div>
                        <div className="form-row"><label>Durée max d'appel (secondes)</label>
                            <input type="number" min="60" max="3600" disabled={!editMode} value={form.max_call_duration} onChange={e => setForm(f => ({ ...f, max_call_duration: parseInt(e.target.value || '600') }))} />
                        </div>
                        <label className="toggle-row">
                            <input type="checkbox" disabled={!editMode} checked={form.learn_from_calls} onChange={e => setForm(f => ({ ...f, learn_from_calls: e.target.checked }))} />
                            <span>Apprendre automatiquement des conversations (extraction Q/R)</span>
                        </label>
                        <label className="toggle-row">
                            <input type="checkbox" disabled={!editMode} checked={form.is_active} onChange={e => setForm(f => ({ ...f, is_active: e.target.checked }))} />
                            <span>Bot actif</span>
                        </label>

                        {editMode && (
                            <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end', marginTop: '0.5rem' }}>
                                <button className="btn btn-secondary" onClick={() => { setEditMode(false); load(); }} disabled={saving}>Annuler</button>
                                <button className="btn btn-primary" onClick={save} disabled={saving}>{saving ? 'Enregistrement…' : 'Enregistrer'}</button>
                            </div>
                        )}
                    </div>
                </div>
            )}

            {tab === 'sources' && <BotSourcesPanel botId={botId} />}
            {tab === 'knowledge' && <BotKnowledgePanel botId={botId} />}
            {tab === 'learnings' && <BotLearningsPanel botId={botId} />}
            {tab === 'conversations' && <BotConversationsPanel botId={botId} />}
            {tab === 'appointments' && <BotAppointmentsPanel botId={botId} form={form} setForm={setForm} editMode={editMode} setEditMode={setEditMode} saving={saving} onSave={save} onCancel={() => { setEditMode(false); load(); }} />}
            {tab === 'leads' && <BotLeadPanel botId={botId} form={form} setForm={setForm} editMode={editMode} setEditMode={setEditMode} saving={saving} onSave={save} onCancel={() => { setEditMode(false); load(); }} />}
            {tab === 'voice' && <BotVoicePanel form={form} setForm={setForm} editMode={editMode} setEditMode={setEditMode} saving={saving} onSave={save} onCancel={() => { setEditMode(false); load(); }} />}
        </div>
    );
};

// ==================== BOT APPOINTMENTS PANEL ====================
const BotAppointmentsPanel = ({ botId, form, setForm, editMode, setEditMode, saving, onSave, onCancel }) => {
    const { notify } = useApp();
    const [appts, setAppts] = useState([]);
    const [loading, setLoading] = useState(true);
    const load = useCallback(async () => {
        setLoading(true);
        try { const r = await api.get(`/my/bots/${botId}/appointments`); setAppts(r?.appointments || []); }
        catch (e) {} finally { setLoading(false); }
    }, [botId]);
    useEffect(() => { load(); }, [load]);
    return (
        <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
            <div className="card-flat">
                <div className="card-flat-header">
                    <Icons.Calendar className="w-5 h-5" />
                    <h2>Configuration RDV</h2>
                    {!editMode && <button className="btn btn-primary btn-sm" style={{ marginLeft: 'auto' }} onClick={() => setEditMode(true)}>Modifier</button>}
                </div>
                <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
                    <label className="toggle-row">
                        <input type="checkbox" disabled={!editMode} checked={form.appointments_enabled}
                            onChange={e => setForm(f => ({ ...f, appointments_enabled: e.target.checked }))} />
                        <span>Le bot peut prendre des rendez-vous (tool calling)</span>
                    </label>
                    {form.appointments_enabled && (
                        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '0.75rem' }}>
                            <div className="form-row"><label>Durée (min)</label><input type="number" min="5" max="240" disabled={!editMode} value={form.appointment_duration_minutes} onChange={e => setForm(f => ({ ...f, appointment_duration_minutes: parseInt(e.target.value) || 30 }))} /></div>
                            <div className="form-row"><label>Pause entre RDV (min)</label><input type="number" min="0" max="60" disabled={!editMode} value={form.appointment_buffer_minutes} onChange={e => setForm(f => ({ ...f, appointment_buffer_minutes: parseInt(e.target.value) || 0 }))} /></div>
                            <div className="form-row"><label>Email de notification</label><input type="email" disabled={!editMode} value={form.appointment_notify_email} onChange={e => setForm(f => ({ ...f, appointment_notify_email: e.target.value }))} placeholder="vous@exemple.ch" /></div>
                            <div className="form-row"><label>Jours max d'avance</label><input type="number" min="1" max="120" disabled={!editMode} value={form.appointment_max_days_ahead} onChange={e => setForm(f => ({ ...f, appointment_max_days_ahead: parseInt(e.target.value) || 30 }))} /></div>
                            <div className="form-row" style={{ gridColumn: '1 / -1' }}>
                                <label>Plages horaires (JSON, ex: {'{"monday":{"open":true,"from":"09:00","to":"18:00"},...}'} - vide = 9h-18h L-V)</label>
                                <textarea rows={3} disabled={!editMode} value={form.appointment_business_hours} onChange={e => setForm(f => ({ ...f, appointment_business_hours: e.target.value }))} />
                            </div>
                        </div>
                    )}
                    {editMode && (
                        <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end' }}>
                            <button className="btn btn-secondary" onClick={onCancel} disabled={saving}>Annuler</button>
                            <button className="btn btn-primary" onClick={onSave} disabled={saving}>{saving ? 'Enregistrement…' : 'Enregistrer'}</button>
                        </div>
                    )}
                </div>
            </div>
            <div className="card-flat">
                <div className="card-flat-header"><Icons.Calendar className="w-5 h-5" /><h2>RDV pris ({appts.length})</h2><button className="btn btn-secondary btn-sm" style={{ marginLeft: 'auto' }} onClick={load}><Icons.Refresh className="w-4 h-4" /></button></div>
                <div className="card-flat-content">
                    {loading ? <p>Chargement…</p> : appts.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>Aucun rendez-vous pour l'instant.</p> : (
                        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.875rem' }}>
                            <thead><tr style={{ textAlign: 'left', color: 'var(--text-muted)' }}><th style={{ padding: '0.5rem 0' }}>Date</th><th>Personne</th><th>Téléphone</th><th>Motif</th><th>Statut</th><th></th></tr></thead>
                            <tbody>
                                {appts.map(a => (
                                    <tr key={a.id} style={{ borderTop: '1px solid var(--border)' }}>
                                        <td style={{ padding: '0.5rem 0' }}><strong>{new Date(a.slot_start).toLocaleString('fr-CH', { weekday: 'short', day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })}</strong></td>
                                        <td>{a.attendee_name}</td>
                                        <td style={{ fontFamily: 'ui-monospace, monospace', color: 'var(--text-muted)' }}>{a.attendee_phone || '-'}</td>
                                        <td style={{ color: 'var(--text-muted)' }}>{a.purpose || '-'}</td>
                                        <td>{a.status}</td>
                                        <td><button className="btn btn-secondary btn-sm" onClick={async () => { if (!confirm('Annuler ce RDV ?')) return; await api.del(`/my/bots/${botId}/appointments/${a.id}`); load(); }}><Icons.Trash className="w-4 h-4" /></button></td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    )}
                </div>
            </div>
        </div>
    );
};

// ==================== BOT LEAD SCORING PANEL ====================
const BotLeadPanel = ({ botId, form, setForm, editMode, setEditMode, saving, onSave, onCancel }) => {
    const { notify } = useApp();
    const [stats, setStats] = useState({ stats: {}, top_leads: [] });
    const [loading, setLoading] = useState(true);
    const load = useCallback(async () => {
        setLoading(true);
        try { const r = await api.get(`/my/bots/${botId}/lead-stats`); setStats(r); }
        catch (e) {} finally { setLoading(false); }
    }, [botId]);
    useEffect(() => { load(); }, [load]);
    return (
        <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
            <div className="card-flat">
                <div className="card-flat-header">
                    <Icons.AlertCircle className="w-5 h-5" />
                    <h2>Configuration Lead Scoring (BANT)</h2>
                    {!editMode && <button className="btn btn-primary btn-sm" style={{ marginLeft: 'auto' }} onClick={() => setEditMode(true)}>Modifier</button>}
                </div>
                <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
                    <label className="toggle-row">
                        <input type="checkbox" disabled={!editMode} checked={form.lead_scoring_enabled}
                            onChange={e => setForm(f => ({ ...f, lead_scoring_enabled: e.target.checked }))} />
                        <span>Activer le scoring BANT (Budget / Authority / Need / Timing)</span>
                    </label>
                    {form.lead_scoring_enabled && (
                        <div className="form-row">
                            <label>Prompt personnalisé (optionnel, sinon BANT classique)</label>
                            <textarea rows={4} disabled={!editMode} value={form.lead_scoring_prompt} onChange={e => setForm(f => ({ ...f, lead_scoring_prompt: e.target.value }))}
                                placeholder="Tu analyses la conversation et tu attribues 0-25 points sur chaque critère…" />
                        </div>
                    )}
                    {editMode && (
                        <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end' }}>
                            <button className="btn btn-secondary" onClick={onCancel} disabled={saving}>Annuler</button>
                            <button className="btn btn-primary" onClick={onSave} disabled={saving}>{saving ? 'Enregistrement…' : 'Enregistrer'}</button>
                        </div>
                    )}
                </div>
            </div>
            {form.lead_scoring_enabled && (
                <>
                    <div className="card-flat">
                        <div className="card-flat-header"><Icons.AlertCircle className="w-5 h-5" /><h2>Statistiques</h2><button className="btn btn-secondary btn-sm" style={{ marginLeft: 'auto' }} onClick={load}><Icons.Refresh className="w-4 h-4" /></button></div>
                        <div className="card-flat-content">
                            {loading ? <p>Chargement…</p> : (
                                <div className="stats-grid">
                                    <div className="stat-card"><div className="stat-icon orange"><Icons.AlertCircle className="w-6 h-6" /></div><div><div className="stat-label">Total scorés</div><div className="stat-value">{stats.stats?.total || 0}</div></div></div>
                                    <div className="stat-card"><div className="stat-icon" style={{ background: '#fee2e2', color: '#b91c1c' }}><Icons.Sparkles className="w-6 h-6" /></div><div><div className="stat-label">Hot (≥70)</div><div className="stat-value" style={{ color: '#b91c1c' }}>{stats.stats?.hot || 0}</div></div></div>
                                    <div className="stat-card"><div className="stat-icon orange"><Icons.Sparkles className="w-6 h-6" /></div><div><div className="stat-label">Warm (40-69)</div><div className="stat-value" style={{ color: '#f59e0b' }}>{stats.stats?.warm || 0}</div></div></div>
                                    <div className="stat-card"><div className="stat-icon blue"><Icons.Sparkles className="w-6 h-6" /></div><div><div className="stat-label">Cold (&lt;40)</div><div className="stat-value">{stats.stats?.cold || 0}</div></div></div>
                                </div>
                            )}
                        </div>
                    </div>
                    <div className="card-flat">
                        <div className="card-flat-header"><Icons.Sparkles className="w-5 h-5" /><h2>Top leads</h2></div>
                        <div className="card-flat-content">
                            {(stats.top_leads || []).length === 0 ? <p style={{ color: 'var(--text-muted)' }}>Aucun lead scoré.</p> : (
                                <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.875rem' }}>
                                    <thead><tr style={{ textAlign: 'left', color: 'var(--text-muted)' }}><th>Téléphone</th><th>Score</th><th>BANT</th><th>Date</th></tr></thead>
                                    <tbody>
                                        {(stats.top_leads || []).map(l => {
                                            let bd = {}; try { bd = JSON.parse(l.lead_breakdown || '{}'); } catch (e) {}
                                            return (
                                                <tr key={l.id} style={{ borderTop: '1px solid var(--border)' }}>
                                                    <td style={{ padding: '0.5rem 0', fontFamily: 'ui-monospace, monospace' }}>{l.from_number}</td>
                                                    <td><strong style={{ color: l.lead_score >= 70 ? '#b91c1c' : l.lead_score >= 40 ? '#f59e0b' : '#475569' }}>{l.lead_score}</strong></td>
                                                    <td style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>B:{bd.budget||0} A:{bd.authority||0} N:{bd.need||0} T:{bd.timing||0}</td>
                                                    <td style={{ color: 'var(--text-muted)' }}>{new Date(l.created_at).toLocaleDateString('fr-CH')}</td>
                                                </tr>
                                            );
                                        })}
                                    </tbody>
                                </table>
                            )}
                        </div>
                    </div>
                </>
            )}
        </div>
    );
};

// ==================== BOT VOICE PANEL ====================
const BotVoicePanel = ({ form, setForm, editMode, setEditMode, saving, onSave, onCancel }) => {
    const customVoices = ['alloy', 'ash', 'ballad', 'coral', 'echo', 'sage', 'shimmer', 'verse'];
    return (
        <div className="card-flat">
            <div className="card-flat-header">
                <Icons.Sparkles className="w-5 h-5" />
                <h2>Voix personnalisée</h2>
                {!editMode && <button className="btn btn-primary btn-sm" style={{ marginLeft: 'auto' }} onClick={() => setEditMode(true)}>Modifier</button>}
            </div>
            <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
                <p style={{ color: 'var(--text-muted)', margin: 0, fontSize: '0.875rem' }}>
                    Au-delà des 6 voix par défaut, vous pouvez utiliser une voix OpenAI Realtime additionnelle. Le clonage de voix (ElevenLabs/Cartesia) sera disponible prochainement.
                </p>
                <div className="form-row">
                    <label>Provider</label>
                    <select disabled={!editMode} value={form.custom_voice_provider || ''} onChange={e => setForm(f => ({ ...f, custom_voice_provider: e.target.value }))}>
                        <option value="">- Voix par défaut (config standard) -</option>
                        <option value="openai">OpenAI Realtime (voix étendue)</option>
                    </select>
                </div>
                {form.custom_voice_provider === 'openai' && (
                    <div className="form-row">
                        <label>Voix</label>
                        <select disabled={!editMode} value={form.custom_voice_id || ''} onChange={e => setForm(f => ({ ...f, custom_voice_id: e.target.value }))}>
                            <option value="">- Choisir -</option>
                            {customVoices.map(v => <option key={v} value={v}>{v}</option>)}
                        </select>
                    </div>
                )}
                {editMode && (
                    <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end' }}>
                        <button className="btn btn-secondary" onClick={onCancel} disabled={saving}>Annuler</button>
                        <button className="btn btn-primary" onClick={onSave} disabled={saving}>{saving ? 'Enregistrement…' : 'Enregistrer'}</button>
                    </div>
                )}
            </div>
        </div>
    );
};

const BotSourcesPanel = ({ botId }) => {
    const { notify } = useApp();
    const [items, setItems] = useState([]);
    const [loading, setLoading] = useState(true);
    const [busy, setBusy] = useState(false);
    const [form, setForm] = useState({ type: 'url', label: '', source_url: '', source_text: '', refresh_interval_minutes: 1440 });

    const load = useCallback(async () => {
        setLoading(true);
        try { const r = await api.get(`/my/bots/${botId}/sources`); setItems(r?.sources || []); }
        catch (e) {} finally { setLoading(false); }
    }, [botId]);
    useEffect(() => { load(); }, [load]);

    const add = async () => {
        if (form.type === 'url' && !form.source_url.trim()) { notify.error('URL requise'); return; }
        if (form.type === 'text' && !form.source_text.trim()) { notify.error('Texte requis'); return; }
        setBusy(true);
        try {
            const r = await api.post(`/my/bots/${botId}/sources`, form);
            if (r?.error) notify.error(r.error);
            else { notify.success('Source ajoutée'); setForm({ type: 'url', label: '', source_url: '', source_text: '', refresh_interval_minutes: 1440 }); load(); }
        } catch (e) { notify.error('Erreur'); }
        finally { setBusy(false); }
    };

    const refresh = async (id) => {
        try {
            const r = await api.post(`/my/bots/${botId}/sources/${id}/refresh`);
            if (r?.error) notify.error(r.error);
            else { notify.success('Scraping déclenché'); setTimeout(load, 1500); }
        } catch (e) { notify.error('Erreur'); }
    };

    const remove = async (id) => {
        if (!confirm('Supprimer cette source ?')) return;
        try { await api.del(`/my/bots/${botId}/sources/${id}`); load(); } catch (e) {}
    };

    return (
        <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
            <div className="card-flat">
                <div className="card-flat-header"><Icons.Plus className="w-5 h-5" /><h2>Nouvelle source</h2></div>
                <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                    <div className="form-row"><label>Type</label>
                        <select value={form.type} onChange={e => setForm(f => ({ ...f, type: e.target.value }))}>
                            <option value="url">Site web (scraping périodique)</option>
                            <option value="text">Texte libre</option>
                        </select>
                    </div>
                    <div className="form-row"><label>Libellé</label>
                        <input type="text" value={form.label} onChange={e => setForm(f => ({ ...f, label: e.target.value }))} placeholder="ex: Page tarifs" />
                    </div>
                    {form.type === 'url' && (
                        <>
                            <div className="form-row"><label>URL</label>
                                <input type="url" value={form.source_url} onChange={e => setForm(f => ({ ...f, source_url: e.target.value }))} placeholder="https://..." />
                            </div>
                            <div className="form-row"><label>Rafraîchissement (minutes)</label>
                                <input type="number" min="60" value={form.refresh_interval_minutes} onChange={e => setForm(f => ({ ...f, refresh_interval_minutes: parseInt(e.target.value || '1440') }))} />
                            </div>
                        </>
                    )}
                    {form.type === 'text' && (
                        <div className="form-row"><label>Texte</label>
                            <textarea rows={6} value={form.source_text} onChange={e => setForm(f => ({ ...f, source_text: e.target.value }))} placeholder="Coller le contenu à apprendre…" />
                        </div>
                    )}
                    <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
                        <button className="btn btn-primary" onClick={add} disabled={busy}>{busy ? 'Ajout…' : 'Ajouter la source'}</button>
                    </div>
                </div>
            </div>

            <div className="card-flat">
                <div className="card-flat-header"><Icons.Globe className="w-5 h-5" /><h2>Sources existantes</h2></div>
                <div className="card-flat-content">
                    {loading ? <p style={{ color: 'var(--text-muted)' }}>Chargement…</p> :
                     items.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>Aucune source.</p> :
                     <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                        {items.map(s => (
                            <div key={s.id} style={{ padding: '0.75rem', border: '1px solid var(--border)', borderRadius: 8, display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
                                <div style={{ flex: 1, minWidth: 0 }}>
                                    <div style={{ display: 'flex', alignItems: 'center', gap: '0.4rem', marginBottom: '0.25rem' }}>
                                        <strong style={{ fontSize: '0.9rem' }}>{s.label || (s.type === 'url' ? s.source_url : 'Texte libre')}</strong>
                                        <span className={`badge ${s.scrape_status === 'ok' ? 'badge-green' : s.scrape_status === 'error' ? 'badge-red' : 'badge-gray'}`} style={{ fontSize: '0.65rem' }}>{s.scrape_status}</span>
                                        {!s.is_active && <span className="badge badge-gray" style={{ fontSize: '0.65rem' }}>inactif</span>}
                                    </div>
                                    {s.source_url && <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)', overflow: 'hidden', textOverflow: 'ellipsis' }}>{s.source_url}</div>}
                                    <div style={{ fontSize: '0.7rem', color: 'var(--text-muted)' }}>
                                        Type: {s.type} · Refresh: {s.refresh_interval_minutes}min
                                        {s.last_scraped_at && ` · Dernier scraping: ${formatDateTime(s.last_scraped_at)}`}
                                    </div>
                                    {s.scrape_error && <div style={{ fontSize: '0.7rem', color: 'var(--danger)' }}>Erreur: {s.scrape_error}</div>}
                                </div>
                                {s.type === 'url' && (
                                    <button className="btn btn-secondary btn-sm" onClick={() => refresh(s.id)} title="Forcer le scraping">
                                        <Icons.Refresh className="w-4 h-4" />
                                    </button>
                                )}
                                <button className="btn btn-secondary btn-sm" onClick={() => remove(s.id)} style={{ color: 'var(--danger)' }} title="Supprimer">
                                    <Icons.Trash className="w-4 h-4" />
                                </button>
                            </div>
                        ))}
                     </div>
                    }
                </div>
            </div>
        </div>
    );
};

const BotKnowledgePanel = ({ botId }) => {
    const { notify } = useApp();
    const [items, setItems] = useState([]);
    const [loading, setLoading] = useState(true);
    const [form, setForm] = useState({ label: '', content: '' });
    const [busy, setBusy] = useState(false);

    const load = useCallback(async () => {
        setLoading(true);
        try { const r = await api.get(`/my/bots/${botId}/knowledge`); setItems(r?.knowledge || []); }
        catch (e) {} finally { setLoading(false); }
    }, [botId]);
    useEffect(() => { load(); }, [load]);

    const add = async () => {
        if (!form.content.trim()) { notify.error('Contenu requis'); return; }
        setBusy(true);
        try {
            const r = await api.post(`/my/bots/${botId}/knowledge`, form);
            if (r?.error) notify.error(r.error);
            else { notify.success('Ajouté'); setForm({ label: '', content: '' }); load(); }
        } catch (e) { notify.error('Erreur'); }
        finally { setBusy(false); }
    };

    const remove = async (id) => {
        if (!confirm('Supprimer ?')) return;
        try { await api.del(`/my/bots/${botId}/knowledge/${id}`); load(); } catch (e) {}
    };

    return (
        <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
            <div className="card-flat">
                <div className="card-flat-header"><Icons.Plus className="w-5 h-5" /><h2>Ajouter une connaissance manuelle</h2></div>
                <div className="card-flat-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                    <div className="form-row"><label>Libellé</label>
                        <input type="text" value={form.label} onChange={e => setForm(f => ({ ...f, label: e.target.value }))} placeholder="ex: Tarifs 2026" />
                    </div>
                    <div className="form-row"><label>Contenu</label>
                        <textarea rows={5} value={form.content} onChange={e => setForm(f => ({ ...f, content: e.target.value }))} />
                    </div>
                    <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
                        <button className="btn btn-primary" onClick={add} disabled={busy}>{busy ? 'Ajout…' : 'Ajouter'}</button>
                    </div>
                </div>
            </div>

            <div className="card-flat">
                <div className="card-flat-header"><Icons.Document className="w-5 h-5" /><h2>Base de connaissance ({items.length})</h2></div>
                <div className="card-flat-content">
                    {loading ? <p style={{ color: 'var(--text-muted)' }}>Chargement…</p> :
                     items.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>Aucun chunk.</p> :
                     <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                        {items.map(k => (
                            <div key={k.id} style={{ padding: '0.75rem', border: '1px solid var(--border)', borderRadius: 8 }}>
                                <div style={{ display: 'flex', alignItems: 'center', gap: '0.4rem', marginBottom: '0.3rem' }}>
                                    {k.label && <strong style={{ fontSize: '0.85rem' }}>{k.label}</strong>}
                                    <span className={`badge ${k.origin === 'manual' ? 'badge-blue' : k.origin === 'scrape' ? 'badge-green' : 'badge-gray'}`} style={{ fontSize: '0.65rem' }}>{k.origin}</span>
                                    <button className="btn btn-secondary btn-sm" style={{ marginLeft: 'auto', color: 'var(--danger)' }} onClick={() => remove(k.id)}>
                                        <Icons.Trash className="w-4 h-4" />
                                    </button>
                                </div>
                                <div style={{ fontSize: '0.8rem', whiteSpace: 'pre-wrap', color: 'var(--text)', maxHeight: 120, overflow: 'auto' }}>{k.content}</div>
                            </div>
                        ))}
                     </div>
                    }
                </div>
            </div>
        </div>
    );
};

const BotLearningsPanel = ({ botId }) => {
    const { notify } = useApp();
    const [items, setItems] = useState([]);
    const [loading, setLoading] = useState(true);
    const [filter, setFilter] = useState('pending');

    const load = useCallback(async () => {
        setLoading(true);
        try { const r = await api.get(`/my/bots/${botId}/learnings?filter=${filter}`); setItems(r?.learnings || []); }
        catch (e) {} finally { setLoading(false); }
    }, [botId, filter]);
    useEffect(() => { load(); }, [load]);

    const validate = async (id, is_validated, is_active = true) => {
        try { await api.put(`/my/bots/${botId}/learnings/${id}`, { is_validated: is_validated ? 1 : 0, is_active: is_active ? 1 : 0 }); load(); } catch (e) {}
    };
    const remove = async (id) => {
        if (!confirm('Supprimer ?')) return;
        try { await api.del(`/my/bots/${botId}/learnings/${id}`); load(); } catch (e) {}
    };

    return (
        <div className="card-flat">
            <div className="card-flat-header">
                <Icons.Sparkles className="w-5 h-5" />
                <h2>Apprentissages automatiques</h2>
                <select value={filter} onChange={e => setFilter(e.target.value)} style={{ marginLeft: 'auto' }}>
                    <option value="pending">À valider</option>
                    <option value="validated">Validés</option>
                    <option value="all">Tous</option>
                </select>
            </div>
            <div className="card-flat-content">
                {loading ? <p style={{ color: 'var(--text-muted)' }}>Chargement…</p> :
                 items.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>Aucun apprentissage.</p> :
                 <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                    {items.map(l => (
                        <div key={l.id} style={{ padding: '0.75rem', border: '1px solid var(--border)', borderRadius: 8 }}>
                            <div style={{ marginBottom: '0.4rem' }}>
                                <strong style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>Q :</strong>
                                <div style={{ fontSize: '0.9rem' }}>{l.question}</div>
                            </div>
                            <div style={{ marginBottom: '0.4rem' }}>
                                <strong style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>R :</strong>
                                <div style={{ fontSize: '0.9rem' }}>{l.answer}</div>
                            </div>
                            <div style={{ display: 'flex', gap: '0.4rem', alignItems: 'center' }}>
                                {!l.is_validated ? (
                                    <button className="btn btn-primary btn-sm" onClick={() => validate(l.id, true, true)}>Valider</button>
                                ) : (
                                    <span className="badge badge-green">Validé</span>
                                )}
                                <button className="btn btn-secondary btn-sm" onClick={() => remove(l.id)} style={{ color: 'var(--danger)', marginLeft: 'auto' }}>
                                    <Icons.Trash className="w-4 h-4" />
                                </button>
                            </div>
                        </div>
                    ))}
                 </div>
                }
            </div>
        </div>
    );
};

const BotConversationsPanel = ({ botId }) => {
    const [items, setItems] = useState([]);
    const [loading, setLoading] = useState(true);
    const [open, setOpen] = useState(null);

    const load = useCallback(async () => {
        setLoading(true);
        try { const r = await api.get(`/my/bots/${botId}/conversations`); setItems(r?.conversations || []); }
        catch (e) {} finally { setLoading(false); }
    }, [botId]);
    useEffect(() => { load(); }, [load]);

    return (
        <div className="card-flat">
            <div className="card-flat-header"><Icons.Phone className="w-5 h-5" /><h2>Conversations ({items.length})</h2></div>
            <div className="card-flat-content">
                {loading ? <p style={{ color: 'var(--text-muted)' }}>Chargement…</p> :
                 items.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>Aucune conversation pour le moment.</p> :
                 <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                    {items.map(c => {
                        const isOpen = open === c.id;
                        return (
                            <div key={c.id} style={{ border: '1px solid var(--border)', borderRadius: 8 }}>
                                <button onClick={() => setOpen(isOpen ? null : c.id)}
                                    style={{ width: '100%', padding: '0.75rem', background: 'transparent', border: 'none', textAlign: 'left', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
                                    <Icons.Phone className="w-4 h-4" />
                                    <div style={{ flex: 1 }}>
                                        <div style={{ fontWeight: 600, fontSize: '0.85rem' }}>{c.from_number || '-'} → {c.to_number || '-'}</div>
                                        <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>
                                            {formatDateTime(c.created_at)} · {formatDuration(c.duration || 0)} · {c.status}
                                        </div>
                                    </div>
                                </button>
                                {isOpen && (
                                    <div style={{ padding: '0.75rem', borderTop: '1px solid var(--border)', background: '#f8fafc' }}>
                                        {c.summary && (
                                            <div style={{ marginBottom: '0.5rem' }}>
                                                <strong style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>Résumé</strong>
                                                <div style={{ fontSize: '0.85rem' }}>{c.summary}</div>
                                            </div>
                                        )}
                                        {c.transcript && (
                                            <div>
                                                <strong style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>Transcript</strong>
                                                <pre style={{ fontSize: '0.8rem', whiteSpace: 'pre-wrap', fontFamily: 'inherit', margin: 0, marginTop: '0.25rem', maxHeight: 300, overflow: 'auto' }}>{c.transcript}</pre>
                                            </div>
                                        )}
                                    </div>
                                )}
                            </div>
                        );
                    })}
                 </div>
                }
            </div>
        </div>
    );
};

// ==================== BILLING (Crédits) ====================
const BillingView = () => {
    const { notify } = useApp();
    const [balance, setBalance] = useState(null);
    const [transactions, setTransactions] = useState([]);
    const [recharges, setRecharges] = useState([]);
    const [loading, setLoading] = useState(true);
    const [customAmount, setCustomAmount] = useState('');
    const [busy, setBusy] = useState(false);
    const [tab, setTab] = useState('packs');

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const [b, t, r] = await Promise.all([
                api.get('/my/billing/balance'),
                api.get('/my/billing/transactions?limit=100'),
                api.get('/my/billing/recharges'),
            ]);
            if (b?.error) notify.error(b.error);
            setBalance(b);
            setTransactions(t?.transactions || []);
            setRecharges(r?.recharges || []);
        } catch (e) { notify.error('Erreur'); }
        finally { setLoading(false); }
    }, [notify]);

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

    const recharge = async (payload) => {
        setBusy(true);
        try {
            const r = await api.post('/my/billing/recharge', payload);
            if (r?.error) { notify.error(r.error); return; }
            if (r.checkout_url) window.location.href = r.checkout_url;
        } catch (e) { notify.error(e.message); }
        finally { setBusy(false); }
    };

    const balanceColor = balance?.balance < (balance?.critical_threshold || 1) ? '#dc2626'
        : balance?.balance < (balance?.low_threshold || 5) ? '#d97706' : '#16a34a';

    const txTypeLabel = (t) => ({
        recharge: 'Recharge', bonus: 'Bonus offert',
        debit_call: 'Appel', debit_sms: 'SMS', debit_whatsapp: 'WhatsApp',
        refund: 'Remboursement', adjustment: 'Ajustement',
    })[t] || t;

    const txTypeBadge = (t) => ({
        recharge: 'badge-success', bonus: 'badge-success',
        debit_call: 'badge-info', debit_sms: 'badge-info', debit_whatsapp: 'badge-info',
        refund: 'badge-warning', adjustment: 'badge-gray',
    })[t] || 'badge-gray';

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Crédits</h1>
                    <p className="page-subtitle">Rechargez votre wallet pour passer des appels et envoyer des SMS</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={load}><Icons.Refresh className="w-4 h-4" /> Actualiser</button>
                </div>
            </div>
            <div className="page-content">
                {/* Balance card */}
                <div className="card" style={{ padding: '2rem', marginBottom: '1.5rem', background: 'linear-gradient(135deg, #eef2ff 0%, #f0f9ff 100%)', border: '1px solid #c7d2fe' }}>
                    <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', flexWrap: 'wrap', gap: '1rem' }}>
                        <div>
                            <div style={{ fontSize: '0.875rem', color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.05em', fontWeight: 600 }}>Solde disponible</div>
                            {loading ? (
                                <Skeleton width={200} height={48} style={{ marginTop: '0.5rem' }} />
                            ) : (
                                <div style={{ fontSize: '3rem', fontWeight: 800, color: balanceColor, marginTop: '0.25rem', lineHeight: 1.1 }}>
                                    {(balance?.balance || 0).toFixed(2)} <span style={{ fontSize: '1.5rem', color: 'var(--text-muted)' }}>{balance?.currency || 'CHF'}</span>
                                </div>
                            )}
                            {balance && balance.balance <= balance.critical_threshold && (
                                <div style={{ marginTop: '0.75rem', display: 'flex', alignItems: 'center', gap: '0.4rem', color: '#dc2626', fontSize: '0.875rem', fontWeight: 600 }}>
                                    <Icons.AlertTriangle className="w-4 h-4" /> Solde critique • rechargez pour éviter toute interruption
                                </div>
                            )}
                            {balance && balance.balance > balance.critical_threshold && balance.balance <= balance.low_threshold && (
                                <div style={{ marginTop: '0.75rem', color: '#d97706', fontSize: '0.875rem', fontWeight: 500 }}>
                                    ⚠ Solde faible • pensez à recharger
                                </div>
                            )}
                        </div>
                        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, auto)', gap: '0.5rem 1.5rem', textAlign: 'right' }}>
                            <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>Total rechargé</div>
                            <div style={{ fontWeight: 600 }}>{formatCurrency(balance?.total_recharged || 0)}</div>
                            <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>Total consommé</div>
                            <div style={{ fontWeight: 600 }}>{formatCurrency(balance?.total_consumed || 0)}</div>
                        </div>
                    </div>
                </div>

                <div style={{ display: 'flex', gap: '0.5rem', marginBottom: '1.25rem', borderBottom: '1px solid var(--border)' }}>
                    {[
                        { id: 'packs', label: 'Recharger' },
                        { id: 'transactions', label: 'Mouvements' },
                        { id: 'recharges', label: 'Mes recharges' },
                    ].map(t => (
                        <button key={t.id} onClick={() => setTab(t.id)}
                            style={{ background: 'none', border: 'none', padding: '0.75rem 1rem', cursor: 'pointer', fontSize: '0.875rem', fontWeight: 500, color: tab === t.id ? 'var(--primary)' : 'var(--text-muted)', borderBottom: tab === t.id ? '2px solid var(--primary)' : '2px solid transparent', marginBottom: '-1px' }}>
                            {t.label}
                        </button>
                    ))}
                </div>

                {tab === 'packs' && balance && (
                    <>
                        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(180px, 1fr))', gap: '1rem', marginBottom: '1.5rem' }}>
                            {(balance.packs || []).map(p => {
                                const popular = p.id === 'pack_45';
                                const total = p.amount + (p.bonus || 0);
                                return (
                                    <button key={p.id} onClick={() => recharge({ pack_id: p.id })} disabled={busy}
                                        style={{ background: '#fff', border: `2px solid ${popular ? 'var(--primary)' : 'var(--border)'}`, borderRadius: '0.75rem', padding: '1.25rem', cursor: busy ? 'not-allowed' : 'pointer', textAlign: 'center', position: 'relative', transition: 'transform 0.15s' }}>
                                        {popular && <span style={{ position: 'absolute', top: -10, left: '50%', transform: 'translateX(-50%)', background: 'var(--primary)', color: '#fff', fontSize: '0.65rem', fontWeight: 700, padding: '0.2rem 0.6rem', borderRadius: '999px', whiteSpace: 'nowrap' }}>POPULAIRE</span>}
                                        <div style={{ fontSize: '2rem', fontWeight: 800, color: 'var(--text-main)' }}>{p.amount}<span style={{ fontSize: '0.85rem', fontWeight: 500, color: 'var(--text-muted)' }}> CHF</span></div>
                                        {p.bonus > 0 && <div style={{ color: '#16a34a', fontWeight: 600, fontSize: '0.8rem', marginTop: '0.4rem' }}>+ {p.bonus} CHF offerts</div>}
                                        <div style={{ marginTop: '0.5rem', fontSize: '0.7rem', color: 'var(--text-muted)' }}>= {total} CHF de crédit</div>
                                    </button>
                                );
                            })}
                        </div>
                        <div className="card" style={{ padding: '1.25rem' }}>
                            <h3 style={{ margin: '0 0 0.5rem', fontSize: '0.95rem', fontWeight: 700 }}>Montant personnalisé</h3>
                            <p style={{ margin: '0 0 0.75rem', color: 'var(--text-muted)', fontSize: '0.8rem' }}>Min. 5 CHF • Max. 1000 CHF</p>
                            <div style={{ display: 'flex', gap: '0.5rem' }}>
                                <input type="number" min="5" max="1000" step="5" className="form-input" value={customAmount} onChange={(e) => setCustomAmount(e.target.value)} placeholder="Ex: 30" style={{ flex: 1, marginBottom: 0 }} />
                                <button className="btn btn-primary" disabled={busy || !customAmount || customAmount < 5} onClick={() => recharge({ amount: parseFloat(customAmount) })}>
                                    {busy ? '…' : 'Recharger'}
                                </button>
                            </div>
                        </div>
                    </>
                )}

                {tab === 'transactions' && (
                    <div className="card" style={{ overflow: 'hidden' }}>
                        {loading ? <SkeletonTable rows={8} cols={4} /> : transactions.length === 0 ? (
                            <div style={{ padding: '3rem 2rem', textAlign: 'center', color: 'var(--text-muted)' }}>Aucun mouvement</div>
                        ) : (
                            <div className="table-container">
                                <table className="data-table">
                                    <thead><tr><th>Date</th><th>Type</th><th>Description</th><th style={{ textAlign: 'right' }}>Montant</th><th style={{ textAlign: 'right' }}>Solde après</th></tr></thead>
                                    <tbody>
                                        {transactions.map(t => (
                                            <tr key={t.id}>
                                                <td style={{ fontSize: '0.8rem' }}>{formatDateTime(t.created_at)}</td>
                                                <td><span className={`badge ${txTypeBadge(t.type)}`}>{txTypeLabel(t.type)}</span></td>
                                                <td style={{ fontSize: '0.8rem', color: 'var(--text-muted)', maxWidth: 320, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{t.description || '-'}</td>
                                                <td style={{ textAlign: 'right', fontWeight: 700, fontSize: '0.85rem', color: t.amount >= 0 ? '#16a34a' : '#dc2626', fontFeatureSettings: '"tnum"' }}>{formatAmount(t.amount, t.currency, true)}</td>
                                                <td style={{ textAlign: 'right', fontSize: '0.8rem', fontFeatureSettings: '"tnum"' }}>{formatCurrency(t.balance_after, t.currency)}</td>
                                            </tr>
                                        ))}
                                    </tbody>
                                </table>
                            </div>
                        )}
                    </div>
                )}

                {tab === 'recharges' && (
                    <div className="card" style={{ overflow: 'hidden' }}>
                        {loading ? <SkeletonTable rows={6} cols={5} /> : recharges.length === 0 ? (
                            <div style={{ padding: '3rem 2rem', textAlign: 'center', color: 'var(--text-muted)' }}>Aucune recharge effectuée</div>
                        ) : (
                            <div className="table-container">
                                <table className="data-table">
                                    <thead><tr><th>Date</th><th>Pack</th><th style={{ textAlign: 'right' }}>Payé</th><th style={{ textAlign: 'right' }}>Bonus</th><th style={{ textAlign: 'right' }}>Crédité</th><th>Statut</th></tr></thead>
                                    <tbody>
                                        {recharges.map(r => (
                                            <tr key={r.id}>
                                                <td style={{ fontSize: '0.8rem' }}>{formatDateTime(r.created_at)}</td>
                                                <td style={{ fontSize: '0.8rem' }}>{r.pack_id || 'Custom'}</td>
                                                <td style={{ textAlign: 'right', fontWeight: 600, fontSize: '0.85rem' }}>{formatCurrency(r.amount, r.currency)}</td>
                                                <td style={{ textAlign: 'right', fontSize: '0.8rem', color: '#16a34a', fontWeight: 600 }}>{r.bonus > 0 ? `+${r.bonus.toFixed(2)}` : '-'}</td>
                                                <td style={{ textAlign: 'right', fontWeight: 700, fontSize: '0.85rem' }}>{formatCurrency(r.total_credited, r.currency)}</td>
                                                <td><span className={`badge ${r.status === 'succeeded' ? 'badge-success' : (r.status === 'pending' ? 'badge-warning' : 'badge-danger')}`}>{r.status}</span></td>
                                            </tr>
                                        ))}
                                    </tbody>
                                </table>
                            </div>
                        )}
                    </div>
                )}
            </div>
        </>
    );
};

// ==================== SUBSCRIPTIONS (vue par ligne) ====================
const SubscriptionsView = () => {
    const { notify, navigate } = useApp();
    const [lines, setLines] = useState([]);
    const [subs, setSubs] = useState([]);
    const [loading, setLoading] = useState(true);

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const [l, s] = await Promise.all([api.get('/my/lines'), api.get('/my/subscriptions')]);
            if (l?.error) notify.error(l.error);
            setLines(l?.lines || []);
            setSubs(s?.subscriptions || []);
        } catch (e) { notify.error('Erreur'); }
        finally { setLoading(false); }
    }, [notify]);

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

    const subByLine = useMemo(() => {
        const m = {};
        for (const s of subs) {
            if (s.status === 'canceled') continue;
            if (!m[s.line_id] || new Date(s.created_at) > new Date(m[s.line_id].created_at)) m[s.line_id] = s;
        }
        return m;
    }, [subs]);

    const active = lines.filter(l => subByLine[l.id]);
    const inactive = lines.filter(l => !subByLine[l.id]);

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Abonnements</h1>
                    <p className="page-subtitle">Gérez les abonnements de location de vos numéros</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={load}><Icons.Refresh className="w-4 h-4" /> Actualiser</button>
                </div>
            </div>
            <div className="page-content">
                {loading ? <SkeletonCards count={3} columns={1} /> : (
                    <>
                        {active.length > 0 && (
                            <>
                                <h3 style={{ margin: '0 0 0.75rem', fontSize: '0.9rem', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.05em', color: 'var(--text-muted)' }}>Lignes avec abonnement actif ({active.length})</h3>
                                <div style={{ display: 'grid', gap: '0.75rem', marginBottom: '2rem' }}>
                                    {active.map(l => {
                                        const s = subByLine[l.id];
                                        const isPastDue = s.status === 'past_due';
                                        return (
                                            <div key={l.id} className="card" style={{ padding: '1.25rem', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '1rem', flexWrap: 'wrap', cursor: 'pointer' }}
                                                onClick={() => navigate('line-detail', { lineId: l.id })}>
                                                <div style={{ flex: 1, minWidth: 240 }}>
                                                    <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', marginBottom: '0.25rem' }}>
                                                        <span style={{ fontWeight: 700, fontFamily: 'ui-monospace, monospace', fontSize: '0.95rem' }}>{l.phone_number}</span>
                                                        {l.label && <span style={{ color: 'var(--text-muted)', fontSize: '0.8rem' }}>· {l.label}</span>}
                                                    </div>
                                                    <div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
                                                        <span className={`badge ${s.status === 'active' || s.status === 'trialing' ? 'badge-success' : 'badge-warning'}`}>
                                                            {s.billing_period === 'yearly' ? 'Annuel' : 'Mensuel'} • {s.status}
                                                        </span>
                                                        {s.cancel_at_period_end ? <span className="badge badge-warning">Annulation programmée</span> : null}
                                                        {isPastDue && <span className="badge badge-danger">Paiement échoué</span>}
                                                    </div>
                                                </div>
                                                <div style={{ textAlign: 'right' }}>
                                                    <div style={{ fontWeight: 700, fontSize: '0.95rem' }}>{formatCurrency(s.amount, s.currency)}</div>
                                                    <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>par {s.billing_period === 'yearly' ? 'an' : 'mois'}</div>
                                                    {s.current_period_end && <div style={{ fontSize: '0.7rem', color: 'var(--text-muted)', marginTop: '0.25rem' }}>Renouv. {formatDate(s.current_period_end)}</div>}
                                                </div>
                                            </div>
                                        );
                                    })}
                                </div>
                            </>
                        )}

                        {inactive.length > 0 && (
                            <>
                                <h3 style={{ margin: '0 0 0.75rem', fontSize: '0.9rem', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.05em', color: 'var(--text-muted)' }}>Lignes sans abonnement ({inactive.length})</h3>
                                <div style={{ display: 'grid', gap: '0.75rem' }}>
                                    {inactive.map(l => (
                                        <div key={l.id} className="card" style={{ padding: '1.25rem', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '1rem', flexWrap: 'wrap' }}>
                                            <div>
                                                <div style={{ fontWeight: 700, fontFamily: 'ui-monospace, monospace', fontSize: '0.95rem' }}>{l.phone_number}</div>
                                                {l.label && <div style={{ color: 'var(--text-muted)', fontSize: '0.8rem' }}>{l.label}</div>}
                                            </div>
                                            <button className="btn btn-primary btn-sm" onClick={() => navigate('line-detail', { lineId: l.id })}>
                                                <Icons.Plus className="w-4 h-4" /> Souscrire
                                            </button>
                                        </div>
                                    ))}
                                </div>
                            </>
                        )}

                        {lines.length === 0 && (
                            <div className="card" style={{ padding: '4rem 2rem', textAlign: 'center' }}>
                                <Icons.Card className="w-12 h-12" style={{ margin: '0 auto 1rem', opacity: 0.4, color: 'var(--text-muted)' }} />
                                <p style={{ margin: 0, color: 'var(--text-muted)' }}>Vous n'avez pas encore de ligne. Contactez Vocal pour en obtenir une.</p>
                            </div>
                        )}
                    </>
                )}
            </div>
        </>
    );
};

// ==================== CALLS ====================
const CallsView = () => {
    const { notify } = useApp();
    const [calls, setCalls] = useState({ calls: [], total: 0, page: 1, total_pages: 1 });
    const [lines, setLines] = useState([]);
    const [loading, setLoading] = useState(true);
    const [refreshing, setRefreshing] = useState(false);
    const [page, setPage] = useState(1);
    const [filterLine, setFilterLine] = useState('');
    const [filterStatus, setFilterStatus] = useState('');
    const [filterDirection, setFilterDirection] = useState('');
    const [search, setSearch] = useState('');
    const debouncedSearch = useDebouncedValue(search, 350);
    const [expanded, setExpanded] = useState(null);
    const reqIdRef = useRef(0);
    const initialRef = useRef(true);

    const buildUrl = useCallback((p) => {
        const params = new URLSearchParams();
        params.set('page', String(p));
        params.set('limit', '30');
        if (filterLine) params.set('line_id', filterLine);
        if (filterStatus) params.set('status', filterStatus);
        if (filterDirection) params.set('direction', filterDirection);
        if (debouncedSearch.trim()) params.set('q', debouncedSearch.trim());
        return `/my/calls?${params.toString()}`;
    }, [filterLine, filterStatus, filterDirection, debouncedSearch]);

    const load = useCallback(async (p, opts = {}) => {
        const id = ++reqIdRef.current;
        if (opts.background) setRefreshing(true); else setLoading(true);
        try {
            const data = await api.get(buildUrl(p));
            if (id !== reqIdRef.current) return;
            if (data?.error) notify.error(data.error);
            setCalls(data || { calls: [], total: 0, page: 1, total_pages: 1 });
        } catch (e) { if (id === reqIdRef.current) notify.error('Erreur chargement appels'); }
        finally { if (id === reqIdRef.current) { setLoading(false); setRefreshing(false); } }
    }, [buildUrl, notify]);

    useEffect(() => {
        (async () => {
            try { const data = await api.get('/my/lines'); setLines(data?.lines || []); } catch (e) {}
        })();
    }, []);

    useEffect(() => {
        if (page !== 1) { setPage(1); return; }
        load(1);
    }, [filterLine, filterStatus, filterDirection, debouncedSearch]);

    useEffect(() => { load(page, { background: !initialRef.current }); initialRef.current = false; }, [page]);

    const visible = calls.calls || [];
    const handlePage = (p) => { if (p >= 1 && p <= calls.total_pages) setPage(p); };

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Appels</h1>
                    <p className="page-subtitle">{calls.total} appels au total</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={() => load(page, { background: true })} disabled={refreshing}>
                        <Icons.Refresh className="w-4 h-4" /> {refreshing ? 'Mise à jour...' : 'Actualiser'}
                    </button>
                </div>
            </div>
            <div className="page-content">
                <div className="card" style={{ overflow: 'hidden' }}>
                    <div style={{ padding: '1rem 1.25rem', borderBottom: '1px solid var(--border)', display: 'flex', gap: '0.75rem', flexWrap: 'wrap', alignItems: 'center' }}>
                        <div style={{ position: 'relative', flex: '1 1 200px', minWidth: '160px' }}>
                            <Icons.Search className="w-4 h-4" style={{ position: 'absolute', left: '0.75rem', top: '50%', transform: 'translateY(-50%)', color: 'var(--text-muted)' }} />
                            <input className="form-input" placeholder="Rechercher un numéro..." value={search} onChange={(e) => setSearch(e.target.value)}
                                style={{ paddingLeft: '2.25rem', marginBottom: 0 }} />
                        </div>
                        <select className="form-input" style={{ flex: '0 0 auto', width: 'auto', minWidth: '160px', marginBottom: 0 }}
                            value={filterLine} onChange={(e) => setFilterLine(e.target.value)}>
                            <option value="">Toutes mes lignes</option>
                            {lines.map(l => <option key={l.id} value={l.id}>{l.phone_number} {l.label ? `(${l.label})` : ''}</option>)}
                        </select>
                        <select className="form-input" style={{ flex: '0 0 auto', width: 'auto', minWidth: '140px', marginBottom: 0 }}
                            value={filterStatus} onChange={(e) => setFilterStatus(e.target.value)}>
                            <option value="">Tous statuts</option>
                            <option value="missed">Manqués</option>
                            {Object.entries(CALL_STATUS).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
                        </select>
                        <select className="form-input" style={{ flex: '0 0 auto', width: 'auto', minWidth: '130px', marginBottom: 0 }}
                            value={filterDirection} onChange={(e) => setFilterDirection(e.target.value)}>
                            <option value="">Entrants + Sortants</option>
                            <option value="inbound">Entrants</option>
                            <option value="outbound">Sortants</option>
                        </select>
                    </div>

                    {loading ? (
                        <SkeletonTable rows={10} cols={7} />
                    ) : visible.length === 0 ? (
                        <div style={{ padding: '4rem 2rem', textAlign: 'center' }}>
                            <Icons.Phone className="w-10 h-10" style={{ margin: '0 auto 0.75rem', opacity: 0.4, color: 'var(--text-muted)' }} />
                            <p style={{ fontWeight: 600, fontSize: '0.95rem', margin: '0 0 0.25rem' }}>Aucun appel trouvé</p>
                            <p style={{ fontSize: '0.8rem', color: 'var(--text-muted)', margin: 0 }}>Ajustez vos filtres ou attendez de nouveaux appels</p>
                        </div>
                    ) : (
                        <div className="table-container">
                            <table className="data-table">
                                <thead>
                                    <tr>
                                        <th style={{ width: 36 }}></th>
                                        <th>Date</th>
                                        <th>Appelant</th>
                                        <th>Destination</th>
                                        <th>Ligne</th>
                                        <th>Statut</th>
                                        <th style={{ textAlign: 'right' }}>Durée</th>
                                        <th style={{ textAlign: 'right' }}>Coût</th>
                                    </tr>
                                </thead>
                                <tbody style={{ opacity: refreshing ? 0.6 : 1, transition: 'opacity 0.15s ease' }}>
                                    {visible.map(call => {
                                        const st = CALL_STATUS[call.status] || { label: call.status, color: 'badge-gray' };
                                        const isExp = expanded === call.id;
                                        return (
                                            <Fragment key={call.id}>
                                                <tr onClick={() => setExpanded(isExp ? null : call.id)} style={{ cursor: 'pointer' }}>
                                                    <td style={{ textAlign: 'center' }}><CallDirectionIcon direction={call.direction} /></td>
                                                    <td>
                                                        <div style={{ fontWeight: 500, fontSize: '0.8rem' }}>{formatDateShort(call.created_at)}</div>
                                                        <div style={{ fontSize: '0.7rem', color: 'var(--text-muted)' }}>{formatTimeOnly(call.created_at)}</div>
                                                    </td>
                                                    <td style={{ fontFamily: 'ui-monospace, monospace', fontSize: '0.8rem', fontWeight: 600 }}>{call.from_number || '-'}</td>
                                                    <td style={{ fontFamily: 'ui-monospace, monospace', fontSize: '0.8rem', color: 'var(--text-muted)' }}>{call.to_number || '-'}</td>
                                                    <td style={{ fontSize: '0.8rem' }}>{call.line_label || call.line_phone || '-'}</td>
                                                    <td><div style={{ display: 'flex', alignItems: 'center', gap: '0.4rem' }}><CallStatusDot status={call.status} /><span style={{ fontSize: '0.8rem' }}>{st.label}</span></div></td>
                                                    <td style={{ textAlign: 'right', fontWeight: 600, fontSize: '0.85rem', fontFeatureSettings: '"tnum"' }}>{formatDuration(call.duration)}</td>
                                                    <td style={{ textAlign: 'right', fontSize: '0.8rem' }}>
                                                        {call.is_price_synced ? (call.billed_price > 0 ? formatCurrency(call.billed_price, call.billed_currency || 'CHF') : 'Gratuit') : <span style={{ color: 'var(--text-muted)', fontSize: '0.75rem' }}>-</span>}
                                                    </td>
                                                </tr>
                                                {isExp && (
                                                    <tr>
                                                        <td colSpan="8" style={{ padding: 0 }}>
                                                            <div style={{ background: '#f8fafc', padding: '1rem 1.5rem', display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: '1rem', fontSize: '0.8rem', borderTop: '1px solid var(--border)', borderBottom: '1px solid var(--border)' }}>
                                                                <div>
                                                                    <div style={{ color: 'var(--text-muted)', fontSize: '0.7rem', textTransform: 'uppercase', fontWeight: 600 }}>Direction</div>
                                                                    <div>{call.direction === 'outbound' ? 'Sortant' : 'Entrant'}</div>
                                                                </div>
                                                                <div>
                                                                    <div style={{ color: 'var(--text-muted)', fontSize: '0.7rem', textTransform: 'uppercase', fontWeight: 600 }}>Date complète</div>
                                                                    <div>{formatDateTime(call.created_at)}</div>
                                                                </div>
                                                                <div>
                                                                    <div style={{ color: 'var(--text-muted)', fontSize: '0.7rem', textTransform: 'uppercase', fontWeight: 600 }}>Identifiant</div>
                                                                    <div style={{ fontFamily: 'monospace', fontSize: '0.7rem', wordBreak: 'break-all' }}>{call.call_sid || '-'}</div>
                                                                </div>
                                                                {call.recording_url && (
                                                                    <div style={{ gridColumn: '1 / -1' }}>
                                                                        <div style={{ color: 'var(--text-muted)', fontSize: '0.7rem', textTransform: 'uppercase', fontWeight: 600, marginBottom: '0.3rem' }}>Enregistrement</div>
                                                                        <audio controls preload="none" src={call.recording_url} style={{ width: '100%', maxWidth: 500, height: 36 }} />
                                                                        <div style={{ marginTop: '0.25rem' }}>
                                                                            <a href={call.recording_url} target="_blank" rel="noreferrer" style={{ fontSize: '0.7rem', color: 'var(--text-muted)' }}>Télécharger MP3</a>
                                                                        </div>
                                                                    </div>
                                                                )}
                                                                {call.ai_summary && (
                                                                    <div style={{ gridColumn: '1 / -1', background: '#fff', border: '1px solid var(--border)', borderRadius: 8, padding: '0.75rem' }}>
                                                                        <div style={{ display: 'flex', alignItems: 'center', gap: '0.4rem', marginBottom: '0.3rem' }}>
                                                                            <Icons.Sparkles className="w-4 h-4" />
                                                                            <strong style={{ fontSize: '0.75rem' }}>Résumé IA</strong>
                                                                            {call.ai_sentiment && (
                                                                                <span className={`badge ${call.ai_sentiment === 'positive' ? 'badge-green' : call.ai_sentiment === 'negative' ? 'badge-red' : 'badge-gray'}`} style={{ fontSize: '0.65rem' }}>{call.ai_sentiment}</span>
                                                                            )}
                                                                            {call.ai_intent && (
                                                                                <span className="badge badge-blue" style={{ fontSize: '0.65rem' }}>{call.ai_intent}</span>
                                                                            )}
                                                                        </div>
                                                                        <div style={{ fontSize: '0.8rem', whiteSpace: 'pre-wrap', lineHeight: 1.4 }}>{call.ai_summary}</div>
                                                                        {call.ai_tags && (() => {
                                                                            try {
                                                                                const tags = JSON.parse(call.ai_tags);
                                                                                if (Array.isArray(tags) && tags.length) {
                                                                                    return (
                                                                                        <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.25rem', marginTop: '0.4rem' }}>
                                                                                            {tags.map((t, i) => <span key={i} className="badge badge-gray" style={{ fontSize: '0.65rem' }}>{t}</span>)}
                                                                                        </div>
                                                                                    );
                                                                                }
                                                                            } catch (e) {}
                                                                            return null;
                                                                        })()}
                                                                    </div>
                                                                )}
                                                                {call.transcription_text && (
                                                                    <div style={{ gridColumn: '1 / -1', background: '#fff', border: '1px solid var(--border)', borderRadius: 8, padding: '0.75rem' }}>
                                                                        <div style={{ display: 'flex', alignItems: 'center', gap: '0.4rem', marginBottom: '0.3rem' }}>
                                                                            <Icons.Document className="w-4 h-4" />
                                                                            <strong style={{ fontSize: '0.75rem' }}>Transcription</strong>
                                                                        </div>
                                                                        <div style={{ fontSize: '0.8rem', whiteSpace: 'pre-wrap', lineHeight: 1.5, color: 'var(--text)' }}>{call.transcription_text}</div>
                                                                    </div>
                                                                )}
                                                            </div>
                                                        </td>
                                                    </tr>
                                                )}
                                            </Fragment>
                                        );
                                    })}
                                </tbody>
                            </table>
                        </div>
                    )}

                    {calls.total_pages > 1 && (
                        <div style={{ padding: '0.75rem 1.25rem', borderTop: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', background: '#f8fafc' }}>
                            <span style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>{visible.length} sur {calls.total} appels</span>
                            <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
                                <button className="btn btn-secondary btn-sm" onClick={() => handlePage(page - 1)} disabled={page <= 1} style={{ padding: '0.3rem 0.6rem' }}><Icons.ChevronLeft className="w-4 h-4" /></button>
                                <span style={{ fontSize: '0.8rem', fontWeight: 600, minWidth: '80px', textAlign: 'center' }}>{page} / {calls.total_pages}</span>
                                <button className="btn btn-secondary btn-sm" onClick={() => handlePage(page + 1)} disabled={page >= calls.total_pages} style={{ padding: '0.3rem 0.6rem' }}><Icons.ChevronRight className="w-4 h-4" /></button>
                            </div>
                        </div>
                    )}
                </div>
            </div>
        </>
    );
};

// ==================== SMS ====================
const MessagesView = ({ kind }) => {
    const { notify } = useApp();
    const isSms = kind === 'sms';
    const [data, setData] = useState({ items: [], total: 0, page: 1, total_pages: 1 });
    const [loading, setLoading] = useState(true);
    const [refreshing, setRefreshing] = useState(false);
    const [page, setPage] = useState(1);

    const load = useCallback(async (p = page, opts = {}) => {
        if (opts.background) setRefreshing(true); else setLoading(true);
        try {
            const d = await api.get(`/my/${isSms ? 'sms' : 'whatsapp'}?page=${p}&limit=30`);
            if (d?.error) notify.error(d.error);
            const items = (isSms ? d?.sms : d?.whatsapp) || [];
            setData({ items, total: d?.total || 0, page: d?.page || p, total_pages: d?.total_pages || 1 });
        } catch (e) { notify.error('Erreur chargement messages'); }
        finally { setLoading(false); setRefreshing(false); }
    }, [isSms, notify]);

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

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">{isSms ? 'SMS' : 'WhatsApp'}</h1>
                    <p className="page-subtitle">{data.total} message(s)</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={() => load(page, { background: true })} disabled={refreshing}>
                        <Icons.Refresh className="w-4 h-4" /> {refreshing ? 'Mise à jour...' : 'Actualiser'}
                    </button>
                </div>
            </div>
            <div className="page-content">
                <div className="card" style={{ overflow: 'hidden' }}>
                    {loading ? (
                        <SkeletonTable rows={8} cols={isSms ? 6 : 5} />
                    ) : data.items.length === 0 ? (
                        <div style={{ padding: '4rem 2rem', textAlign: 'center', color: 'var(--text-muted)' }}>
                            {isSms ? <Icons.Send className="w-10 h-10" style={{ margin: '0 auto 0.75rem', opacity: 0.4 }} /> : <Icons.Chat className="w-10 h-10" style={{ margin: '0 auto 0.75rem', opacity: 0.4 }} />}
                            <p style={{ fontWeight: 600, fontSize: '0.9rem', margin: 0 }}>Aucun message</p>
                        </div>
                    ) : (
                        <div className="table-container">
                            <table className="data-table">
                                <thead><tr><th>Date</th><th>Destinataire</th>{isSms && <th>Expéditeur</th>}<th>Message</th><th>Ligne</th><th>Statut</th></tr></thead>
                                <tbody style={{ opacity: refreshing ? 0.6 : 1, transition: 'opacity 0.15s' }}>
                                    {data.items.map(m => (
                                        <tr key={m.id}>
                                            <td style={{ whiteSpace: 'nowrap', fontSize: '0.8rem' }}>{formatDateTime(m.created_at)}</td>
                                            <td style={{ fontWeight: 500, fontFamily: 'ui-monospace, monospace', fontSize: '0.8rem' }}>{m.to_number || '-'}</td>
                                            {isSms && <td style={{ fontSize: '0.8rem' }}>{m.sender || '-'}</td>}
                                            <td style={{ fontSize: '0.8rem', maxWidth: '300px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.message || '-'}</td>
                                            <td style={{ fontSize: '0.8rem' }}>{m.line_label || m.line_phone || '-'}</td>
                                            <td><span className={`badge ${m.status === 'sent' ? 'badge-success' : (m.status === 'failed' || m.status === 'error' ? 'badge-danger' : 'badge-gray')}`}>{m.status === 'sent' ? 'Envoyé' : m.status}</span></td>
                                        </tr>
                                    ))}
                                </tbody>
                            </table>
                        </div>
                    )}
                    {data.total_pages > 1 && (
                        <div style={{ padding: '0.75rem 1.25rem', borderTop: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', background: '#f8fafc' }}>
                            <span style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>{data.items.length} sur {data.total}</span>
                            <div style={{ display: 'flex', gap: '0.5rem' }}>
                                <button className="btn btn-secondary btn-sm" onClick={() => setPage(p => Math.max(1, p - 1))} disabled={page <= 1}><Icons.ChevronLeft className="w-4 h-4" /></button>
                                <span style={{ fontSize: '0.8rem', fontWeight: 600, minWidth: '80px', textAlign: 'center' }}>{page} / {data.total_pages}</span>
                                <button className="btn btn-secondary btn-sm" onClick={() => setPage(p => Math.min(data.total_pages, p + 1))} disabled={page >= data.total_pages}><Icons.ChevronRight className="w-4 h-4" /></button>
                            </div>
                        </div>
                    )}
                </div>
            </div>
        </>
    );
};

// ==================== API KEYS ====================
const ApiKeysView = () => {
    const { notify } = useApp();
    const [keys, setKeys] = useState([]);
    const [lines, setLines] = useState([]);
    const [loading, setLoading] = useState(true);
    const [revealed, setRevealed] = useState({});
    const [copied, setCopied] = useState(null);
    const [showCreate, setShowCreate] = useState(false);
    const [newLabel, setNewLabel] = useState('');
    const [newLineIds, setNewLineIds] = useState([]);
    const [creating, setCreating] = useState(false);
    const [createdKey, setCreatedKey] = useState(null);

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const [k, l] = await Promise.all([api.get('/my/api-keys'), api.get('/my/lines')]);
            setKeys(Array.isArray(k) ? k : []);
            setLines(l?.lines || []);
        } catch (e) { notify.error('Erreur chargement clés'); }
        finally { setLoading(false); }
    }, [notify]);

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

    const copy = (text, id) => { navigator.clipboard.writeText(text); setCopied(id); setTimeout(() => setCopied(null), 1800); };
    const mask = (k) => k ? `${k.slice(0, 6)}${'•'.repeat(20)}${k.slice(-4)}` : '';

    const create = async () => {
        if (!newLabel.trim()) return notify.error('Donnez un nom à la clé');
        setCreating(true);
        try {
            const res = await api.post('/my/api-keys', { label: newLabel, line_ids: newLineIds });
            if (res?.error) { notify.error(res.error); return; }
            if (res?.key_value) {
                setCreatedKey(res.key_value);
                setNewLabel('');
                setNewLineIds([]);
                notify.success('Clé créée');
                load();
            }
        } catch (e) { notify.error('Erreur: ' + e.message); }
        finally { setCreating(false); }
    };

    const toggle = async (k) => {
        try {
            await api.put(`/my/api-keys/${k.id}`, { is_active: k.is_active ? 0 : 1 });
            notify.success(k.is_active ? 'Clé désactivée' : 'Clé activée');
            load();
        } catch (e) { notify.error('Erreur'); }
    };

    const remove = async (k) => {
        if (!confirm(`Supprimer la clé "${k.label || k.key_value}" ?`)) return;
        try { await api.del(`/my/api-keys/${k.id}`); notify.success('Clé supprimée'); load(); }
        catch (e) { notify.error('Erreur'); }
    };

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Clés API</h1>
                    <p className="page-subtitle">Intégrez Vocal dans vos applications</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={load}><Icons.Refresh className="w-4 h-4" /> Actualiser</button>
                    <button className="btn btn-primary btn-sm" onClick={() => { setShowCreate(true); setCreatedKey(null); }}>
                        <Icons.Plus className="w-4 h-4" /> Nouvelle clé
                    </button>
                </div>
            </div>
            <div className="page-content">
                <div className="card" style={{ padding: '1rem 1.25rem', marginBottom: '1.5rem', background: '#eef2ff', border: '1px solid #c7d2fe' }}>
                    <div style={{ fontSize: '0.85rem', color: 'var(--text-main)' }}>
                        <strong>Documentation :</strong> Consultez le guide d'intégration sur <a href="https://docs.vocal.ch" target="_blank" rel="noreferrer" style={{ color: 'var(--primary-dark)', fontWeight: 600 }}>docs.vocal.ch</a> pour utiliser ces clés API dans vos applications tierces.
                    </div>
                </div>

                {showCreate && (
                    <div className="card" style={{ padding: '1.25rem', marginBottom: '1.5rem', border: '2px solid var(--primary-light)' }}>
                        {createdKey ? (
                            <>
                                <h3 style={{ margin: '0 0 0.5rem', fontSize: '0.95rem', fontWeight: 700 }}>Clé API créée</h3>
                                <p style={{ margin: '0 0 1rem', fontSize: '0.8rem', color: 'var(--text-muted)' }}>
                                    Copiez cette clé maintenant • elle reste accessible plus tard mais conservez-la précieusement.
                                </p>
                                <div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center', background: '#f8fafc', padding: '0.75rem', borderRadius: '0.5rem', border: '1px solid var(--border)' }}>
                                    <code style={{ flex: 1, fontFamily: 'ui-monospace, monospace', fontSize: '0.85rem', wordBreak: 'break-all' }}>{createdKey}</code>
                                    <button className="btn btn-primary btn-sm" onClick={() => copy(createdKey, 'new')}>
                                        {copied === 'new' ? <><Icons.Check className="w-4 h-4" /> Copié</> : <><Icons.Copy className="w-4 h-4" /> Copier</>}
                                    </button>
                                </div>
                                <div style={{ marginTop: '1rem', textAlign: 'right' }}>
                                    <button className="btn btn-secondary btn-sm" onClick={() => { setShowCreate(false); setCreatedKey(null); }}>Fermer</button>
                                </div>
                            </>
                        ) : (
                            <>
                                <h3 style={{ margin: '0 0 1rem', fontSize: '0.95rem', fontWeight: 700 }}>Nouvelle clé API</h3>
                                <div className="form-group">
                                    <label className="form-label">Nom de la clé</label>
                                    <input className="form-input" value={newLabel} onChange={(e) => setNewLabel(e.target.value)} placeholder="ex: Site web, App mobile, Backoffice..." autoFocus />
                                </div>
                                {lines.length > 0 && (
                                    <div className="form-group">
                                        <label className="form-label">Lignes autorisées (laisser vide = aucune restriction)</label>
                                        <div style={{ display: 'flex', flexDirection: 'column', gap: '0.4rem', maxHeight: 200, overflow: 'auto', border: '1px solid var(--border)', borderRadius: '0.5rem', padding: '0.5rem' }}>
                                            {lines.map(l => (
                                                <label key={l.id} style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', cursor: 'pointer', padding: '0.25rem' }}>
                                                    <input type="checkbox" checked={newLineIds.includes(l.id)} onChange={() => setNewLineIds(prev => prev.includes(l.id) ? prev.filter(x => x !== l.id) : [...prev, l.id])} />
                                                    <span style={{ fontSize: '0.85rem', fontFamily: 'ui-monospace, monospace' }}>{l.phone_number}</span>
                                                    {l.label && <span style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>({l.label})</span>}
                                                </label>
                                            ))}
                                        </div>
                                    </div>
                                )}
                                <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end' }}>
                                    <button className="btn btn-secondary btn-sm" onClick={() => setShowCreate(false)}>Annuler</button>
                                    <button className="btn btn-primary btn-sm" onClick={create} disabled={creating || !newLabel.trim()}>
                                        {creating ? 'Création...' : 'Créer la clé'}
                                    </button>
                                </div>
                            </>
                        )}
                    </div>
                )}

                {loading ? (
                    <SkeletonCards count={3} columns={1} />
                ) : keys.length === 0 ? (
                    <div className="card" style={{ padding: '4rem 2rem', textAlign: 'center' }}>
                        <Icons.Key className="w-12 h-12" style={{ margin: '0 auto 1rem', opacity: 0.4, color: 'var(--text-muted)' }} />
                        <h3 style={{ margin: '0 0 0.5rem', fontWeight: 600 }}>Aucune clé API</h3>
                        <p style={{ margin: 0, color: 'var(--text-muted)', fontSize: '0.875rem' }}>Créez votre première clé pour intégrer Vocal dans votre application.</p>
                        <button className="btn btn-primary" onClick={() => { setShowCreate(true); setCreatedKey(null); }} style={{ marginTop: '1.25rem' }}>
                            <Icons.Plus className="w-4 h-4" /> Nouvelle clé
                        </button>
                    </div>
                ) : (
                    <div style={{ display: 'grid', gap: '0.75rem' }}>
                        {keys.map(k => {
                            const isShown = revealed[k.id];
                            return (
                                <div key={k.id} className="card" style={{ padding: '1rem 1.25rem' }}>
                                    <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', marginBottom: '0.75rem', flexWrap: 'wrap' }}>
                                        <div style={{ flex: 1, minWidth: 200 }}>
                                            <div style={{ fontWeight: 700, fontSize: '0.95rem' }}>{k.label || 'Clé API'}</div>
                                            <div style={{ fontSize: '0.7rem', color: 'var(--text-muted)', marginTop: '0.2rem' }}>
                                                Créée le {formatDate(k.created_at)} · {k.calls_count || 0} appels
                                            </div>
                                        </div>
                                        <span className={`badge ${k.is_active ? 'badge-success' : 'badge-gray'}`}>{k.is_active ? 'Active' : 'Désactivée'}</span>
                                        <button className="btn btn-secondary btn-sm" onClick={() => toggle(k)}>{k.is_active ? 'Désactiver' : 'Réactiver'}</button>
                                        <button className="btn btn-danger btn-sm btn-icon" onClick={() => remove(k)}><Icons.Trash className="w-4 h-4" /></button>
                                    </div>
                                    <div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center', background: '#f8fafc', padding: '0.6rem 0.75rem', borderRadius: '0.5rem', border: '1px solid var(--border)' }}>
                                        <code style={{ flex: 1, fontFamily: 'ui-monospace, monospace', fontSize: '0.8rem', wordBreak: 'break-all' }}>
                                            {isShown ? k.key_value : mask(k.key_value)}
                                        </code>
                                        <button className="btn btn-secondary btn-sm btn-icon" onClick={() => setRevealed(prev => ({ ...prev, [k.id]: !prev[k.id] }))} title={isShown ? 'Masquer' : 'Afficher'}>
                                            {isShown ? <Icons.EyeOff className="w-4 h-4" /> : <Icons.Eye className="w-4 h-4" />}
                                        </button>
                                        <button className="btn btn-secondary btn-sm btn-icon" onClick={() => copy(k.key_value, k.id)} title="Copier">
                                            {copied === k.id ? <Icons.Check className="w-4 h-4" /> : <Icons.Copy className="w-4 h-4" />}
                                        </button>
                                    </div>
                                    {k.line_ids?.length > 0 && (
                                        <div style={{ marginTop: '0.75rem', fontSize: '0.75rem', color: 'var(--text-muted)' }}>
                                            Lignes autorisées : {k.line_ids.map(lid => {
                                                const l = lines.find(x => x.id === lid);
                                                return l ? l.phone_number : `#${lid}`;
                                            }).join(', ')}
                                        </div>
                                    )}
                                </div>
                            );
                        })}
                    </div>
                )}
            </div>
        </>
    );
};

// ==================== SETTINGS ====================
const SettingsView = () => {
    const { user, notify, refreshProfile, logout } = useApp();
    const [form, setForm] = useState({
        name: '', company: '', phone: '',
        weekly_report_enabled: true, weekly_report_email: '',
        low_balance_threshold: '', critical_balance_threshold: '',
    });
    const [savedAt, setSavedAt] = useState(null);
    const [saving, setSaving] = useState(false);
    const [loaded, setLoaded] = useState(false);

    useEffect(() => {
        (async () => {
            try {
                const data = await api.get('/my/profile');
                if (data?.error) notify.error(data.error);
                const c = data?.client || {};
                setForm({
                    name: data?.user?.name || c.name || '',
                    company: c.company || '',
                    phone: c.phone || '',
                    weekly_report_enabled: c.weekly_report_enabled === undefined ? true : !!c.weekly_report_enabled,
                    weekly_report_email: c.weekly_report_email || '',
                    low_balance_threshold: c.low_balance_threshold ?? '',
                    critical_balance_threshold: c.critical_balance_threshold ?? '',
                });
                setSavedAt(c.weekly_report_last_sent_at || null);
            } catch (e) {}
            finally { setLoaded(true); }
        })();
    }, []);

    const save = async () => {
        setSaving(true);
        try {
            const res = await api.put('/my/profile', form);
            if (res?.error) notify.error(res.error);
            else { notify.success('Profil mis à jour'); refreshProfile(); }
        } catch (e) { notify.error('Erreur'); }
        finally { setSaving(false); }
    };

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">Paramètres</h1>
                    <p className="page-subtitle">Gérez votre profil</p>
                </div>
            </div>
            <div className="page-content">
                <div className="card" style={{ padding: '1.5rem', maxWidth: 640, marginBottom: '1.5rem' }}>
                    <h3 style={{ margin: '0 0 1.25rem', fontSize: '1rem', fontWeight: 700 }}>Mes informations</h3>

                    {!loaded ? (
                        <>
                            <Skeleton height={36} style={{ marginBottom: '1rem' }} />
                            <Skeleton height={36} style={{ marginBottom: '1rem' }} />
                            <Skeleton height={36} />
                        </>
                    ) : (
                        <>
                            <div className="form-group">
                                <label className="form-label">Email</label>
                                <input className="form-input" value={user?.email || ''} disabled style={{ opacity: 0.7 }} />
                            </div>
                            <div className="form-group">
                                <label className="form-label">Nom</label>
                                <input className="form-input" value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} placeholder="Votre nom" />
                            </div>
                            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem' }}>
                                <div className="form-group">
                                    <label className="form-label">Téléphone</label>
                                    <input className="form-input" value={form.phone} onChange={(e) => setForm({ ...form, phone: e.target.value })} placeholder="+41..." />
                                </div>
                                <div className="form-group">
                                    <label className="form-label">Entreprise</label>
                                    <input className="form-input" value={form.company} onChange={(e) => setForm({ ...form, company: e.target.value })} placeholder="Nom de votre entreprise" />
                                </div>
                            </div>
                            <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
                                <button className="btn btn-primary" onClick={save} disabled={saving}>{saving ? 'Enregistrement...' : 'Enregistrer'}</button>
                            </div>
                        </>
                    )}
                </div>

                <div className="card" style={{ padding: '1.5rem', maxWidth: 640, marginBottom: '1.5rem' }}>
                    <h3 style={{ margin: '0 0 0.5rem', fontSize: '1rem', fontWeight: 700 }}>Notifications</h3>
                    <p style={{ margin: '0 0 1.25rem', color: 'var(--text-muted)', fontSize: '0.85rem' }}>
                        Recevez automatiquement un rapport d'activité de toutes vos lignes chaque lundi matin.
                    </p>
                    <label style={{ display: 'flex', alignItems: 'center', gap: '0.6rem', padding: '0.5rem 0', cursor: 'pointer' }}>
                        <input type="checkbox" checked={!!form.weekly_report_enabled} onChange={(e) => setForm({ ...form, weekly_report_enabled: e.target.checked })} />
                        <span style={{ fontSize: '0.875rem' }}>Rapport hebdomadaire d'activité par email</span>
                    </label>
                    {form.weekly_report_enabled && (
                        <div className="form-group" style={{ marginTop: '0.75rem' }}>
                            <label className="form-label" style={{ fontSize: '0.75rem' }}>Email du rapport (laisser vide = email du compte)</label>
                            <input type="email" className="form-input" value={form.weekly_report_email} onChange={(e) => setForm({ ...form, weekly_report_email: e.target.value })} placeholder={user?.email || 'vous@exemple.ch'} />
                        </div>
                    )}
                    {savedAt && (
                        <p style={{ margin: '0.5rem 0 0', fontSize: '0.75rem', color: 'var(--text-muted)' }}>
                            Dernier rapport envoyé : {new Date(savedAt + 'Z').toLocaleString('fr-CH', { dateStyle: 'long', timeStyle: 'short' })}
                        </p>
                    )}
                    <h4 style={{ margin: '1.5rem 0 0.5rem', fontSize: '0.85rem', fontWeight: 700, color: 'var(--text)' }}>Seuils d'alerte solde</h4>
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem' }}>
                        <div className="form-group">
                            <label className="form-label" style={{ fontSize: '0.75rem' }}>Solde faible (CHF)</label>
                            <input type="number" step="0.5" className="form-input" value={form.low_balance_threshold} onChange={(e) => setForm({ ...form, low_balance_threshold: e.target.value })} placeholder="5.00" />
                        </div>
                        <div className="form-group">
                            <label className="form-label" style={{ fontSize: '0.75rem' }}>Solde critique (CHF)</label>
                            <input type="number" step="0.5" className="form-input" value={form.critical_balance_threshold} onChange={(e) => setForm({ ...form, critical_balance_threshold: e.target.value })} placeholder="1.00" />
                        </div>
                    </div>
                    <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '0.5rem' }}>
                        <button className="btn btn-primary" onClick={save} disabled={saving}>{saving ? 'Enregistrement...' : 'Enregistrer'}</button>
                    </div>
                </div>

                <div className="card" style={{ padding: '1.5rem', maxWidth: 640 }}>
                    <h3 style={{ margin: '0 0 0.5rem', fontSize: '1rem', fontWeight: 700 }}>Sécurité</h3>
                    <p style={{ margin: '0 0 1rem', color: 'var(--text-muted)', fontSize: '0.85rem' }}>
                        Vous êtes connecté avec un lien magique envoyé à votre email. Aucun mot de passe à gérer.
                    </p>
                    <button className="btn btn-danger" onClick={logout}>Se déconnecter</button>
                </div>
            </div>
        </>
    );
};

// ==================== CONTACTS (CRM) VIEW ====================
const ContactsView = () => {
    const { notify } = useApp();
    const [contacts, setContacts] = useState([]);
    const [duplicates, setDuplicates] = useState([]);
    const [tab, setTab] = useState('list');
    const [loading, setLoading] = useState(true);
    const [q, setQ] = useState('');
    const [filter, setFilter] = useState('');
    const [show, setShow] = useState(false);
    const [draft, setDraft] = useState({ phone_number: '', name: '', company: '', email: '', notes: '', is_vip: false, is_blacklisted: false });
    const [detail, setDetail] = useState(null);

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const params = new URLSearchParams();
            if (q) params.set('q', q);
            if (filter) params.set('filter', filter);
            params.set('limit', '100');
            const r = await api.get(`/my/contacts?${params}`);
            setContacts(r?.contacts || []);
            const d = await api.get('/my/contacts/duplicates?days=14&min_calls=3');
            setDuplicates(d?.duplicates || []);
        } catch (e) { notify.error('Erreur chargement'); } finally { setLoading(false); }
    }, [q, filter, notify]);
    useEffect(() => { load(); }, [load]);

    const create = async () => {
        if (!draft.phone_number.trim()) return notify.error('Numéro requis');
        try { await api.post('/my/contacts', draft); notify.success('Contact ajouté'); setShow(false); setDraft({ phone_number: '', name: '', company: '', email: '', notes: '', is_vip: false, is_blacklisted: false }); load(); }
        catch (e) { notify.error('Erreur: ' + e.message); }
    };

    const openDetail = async (c) => {
        try { const r = await api.get(`/my/contacts/${c.id}`); setDetail(r); }
        catch (e) { notify.error('Erreur'); }
    };

    if (detail) {
        return (
            <>
                <div className="page-header">
                    <div>
                        <button className="btn btn-secondary btn-sm" onClick={() => setDetail(null)}><Icons.ArrowLeft className="w-4 h-4" /> Retour</button>
                        <h1 className="page-title" style={{ marginTop: '0.5rem' }}>{detail.contact.name || detail.contact.phone_number}</h1>
                        <p className="page-subtitle">{detail.contact.phone_number}{detail.contact.company ? ` · ${detail.contact.company}` : ''}</p>
                    </div>
                </div>
                <div className="page-content" style={{ display: 'grid', gridTemplateColumns: 'minmax(300px, 1fr) 2fr', gap: '1rem' }}>
                    <ContactEditCard contact={detail.contact} onSaved={load} onBack={() => setDetail(null)} />
                    <div className="card">
                        <div style={{ padding: '1rem 1.25rem', borderBottom: '1px solid var(--border)', fontWeight: 700 }}>Historique</div>
                        {(detail.calls || []).length === 0 ? (
                            <p style={{ padding: '1rem', color: 'var(--text-muted)' }}>Aucun appel.</p>
                        ) : (
                            <div style={{ maxHeight: '70vh', overflow: 'auto' }}>
                                {detail.calls.map(c => (
                                    <div key={c.id} style={{ padding: '0.75rem 1rem', borderBottom: '1px solid var(--border)', fontSize: '0.85rem' }}>
                                        <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                                            <strong>{c.direction === 'inbound' ? '↓ Entrant' : '↑ Sortant'} · {c.status}</strong>
                                            <span style={{ color: 'var(--text-muted)' }}>{new Date(c.created_at).toLocaleString('fr-CH')}</span>
                                        </div>
                                        {c.ai_summary && <div style={{ marginTop: '0.4rem', color: '#475569', fontStyle: 'italic' }}>{c.ai_summary}</div>}
                                    </div>
                                ))}
                            </div>
                        )}
                    </div>
                </div>
            </>
        );
    }

    return (
        <>
            <div className="page-header">
                <div><h1 className="page-title">Contacts</h1><p className="page-subtitle">CRM minimaliste basé sur vos appels & SMS</p></div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={load}><Icons.Refresh className="w-4 h-4" /> Actualiser</button>
                    <button className="btn btn-primary btn-sm" onClick={() => setShow(true)}><Icons.Plus className="w-4 h-4" /> Nouveau contact</button>
                </div>
            </div>
            <div className="page-content">
                <div style={{ display: 'flex', gap: '0.5rem', marginBottom: '1rem', borderBottom: '1px solid var(--border)' }}>
                    {[{ id: 'list', label: `Tous (${contacts.length})` }, { id: 'dup', label: `Appelants fréquents (${duplicates.length})` }].map(t => (
                        <button key={t.id} onClick={() => setTab(t.id)}
                            style={{ background: 'none', border: 'none', padding: '0.6rem 1rem', cursor: 'pointer', fontWeight: 500, color: tab === t.id ? 'var(--primary)' : 'var(--text-muted)', borderBottom: tab === t.id ? '2px solid var(--primary)' : '2px solid transparent', marginBottom: '-1px' }}>
                            {t.label}
                        </button>
                    ))}
                </div>
                {tab === 'list' && (
                    <>
                        <div style={{ display: 'flex', gap: '0.5rem', marginBottom: '1rem' }}>
                            <input className="form-input" placeholder="Rechercher (nom, téléphone, email…)" value={q} onChange={e => setQ(e.target.value)} style={{ flex: 1 }} />
                            <select className="form-input" value={filter} onChange={e => setFilter(e.target.value)} style={{ width: 180 }}>
                                <option value="">Tous</option>
                                <option value="vip">VIP uniquement</option>
                                <option value="blacklisted">Blacklistés</option>
                                <option value="recent">Récents (30j)</option>
                            </select>
                        </div>
                        {show && (
                            <div className="card" style={{ padding: '1rem', marginBottom: '1rem', border: '2px solid var(--primary-light)' }}>
                                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '0.75rem' }}>
                                    <div className="form-row"><label>Numéro *</label><input className="form-input" value={draft.phone_number} onChange={e => setDraft({ ...draft, phone_number: e.target.value })} placeholder="+41 79 …" /></div>
                                    <div className="form-row"><label>Nom</label><input className="form-input" value={draft.name} onChange={e => setDraft({ ...draft, name: e.target.value })} /></div>
                                    <div className="form-row"><label>Société</label><input className="form-input" value={draft.company} onChange={e => setDraft({ ...draft, company: e.target.value })} /></div>
                                    <div className="form-row"><label>Email</label><input className="form-input" type="email" value={draft.email} onChange={e => setDraft({ ...draft, email: e.target.value })} /></div>
                                    <div className="form-row" style={{ gridColumn: '1 / -1' }}><label>Notes</label><textarea className="form-input" rows={2} value={draft.notes} onChange={e => setDraft({ ...draft, notes: e.target.value })} /></div>
                                </div>
                                <div style={{ display: 'flex', gap: '1rem', marginTop: '0.5rem' }}>
                                    <label className="toggle-row"><input type="checkbox" checked={draft.is_vip} onChange={e => setDraft({ ...draft, is_vip: e.target.checked })} /><span>VIP</span></label>
                                    <label className="toggle-row"><input type="checkbox" checked={draft.is_blacklisted} onChange={e => setDraft({ ...draft, is_blacklisted: e.target.checked })} /><span>Blacklisté</span></label>
                                </div>
                                <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end', marginTop: '0.75rem' }}>
                                    <button className="btn btn-secondary" onClick={() => setShow(false)}>Annuler</button>
                                    <button className="btn btn-primary" onClick={create}>Créer</button>
                                </div>
                            </div>
                        )}
                        {loading ? <p>Chargement…</p> : contacts.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>Aucun contact pour l'instant.</p> : (
                            <div className="card">
                                <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.875rem' }}>
                                    <thead><tr style={{ background: '#f8fafc', textAlign: 'left' }}>
                                        <th style={{ padding: '0.75rem 1rem' }}>Nom</th><th>Téléphone</th><th>Société</th><th style={{ textAlign: 'right' }}>Appels</th><th>Dernier contact</th><th></th>
                                    </tr></thead>
                                    <tbody>
                                        {contacts.map(c => (
                                            <tr key={c.id} style={{ borderTop: '1px solid var(--border)', cursor: 'pointer' }} onClick={() => openDetail(c)}>
                                                <td style={{ padding: '0.6rem 1rem', fontWeight: 600 }}>
                                                    {c.is_vip && <span style={{ marginRight: 6, color: '#f59e0b' }} title="VIP">★</span>}
                                                    {c.is_blacklisted && <span style={{ marginRight: 6, color: '#dc2626' }} title="Blacklisté">⊘</span>}
                                                    {c.name || '-'}
                                                </td>
                                                <td style={{ fontFamily: 'ui-monospace, monospace', color: 'var(--text-muted)' }}>{c.phone_number}</td>
                                                <td>{c.company || '-'}</td>
                                                <td style={{ textAlign: 'right', fontWeight: 600 }}>{c.total_calls || 0}</td>
                                                <td style={{ color: 'var(--text-muted)', fontSize: '0.8rem' }}>{c.last_contact_at ? new Date(c.last_contact_at).toLocaleDateString('fr-CH') : '-'}</td>
                                                <td></td>
                                            </tr>
                                        ))}
                                    </tbody>
                                </table>
                            </div>
                        )}
                    </>
                )}
                {tab === 'dup' && (
                    <div className="card" style={{ padding: '1rem' }}>
                        <p style={{ color: 'var(--text-muted)', margin: '0 0 1rem' }}>Numéros qui ont rappelé au moins 3 fois en 14 jours.</p>
                        {duplicates.length === 0 ? <p>Aucun appelant fréquent.</p> : (
                            <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.875rem' }}>
                                <thead><tr style={{ textAlign: 'left', color: 'var(--text-muted)' }}><th>Numéro</th><th>Nom</th><th style={{ textAlign: 'right' }}>Appels</th><th>Dernier</th><th></th></tr></thead>
                                <tbody>
                                    {duplicates.map(d => (
                                        <tr key={d.phone_number} style={{ borderTop: '1px solid var(--border)' }}>
                                            <td style={{ padding: '0.5rem 0', fontFamily: 'ui-monospace, monospace' }}>{d.phone_number}</td>
                                            <td>{d.name || '-'}</td>
                                            <td style={{ textAlign: 'right' }}><strong>{d.calls_count}</strong></td>
                                            <td style={{ color: 'var(--text-muted)' }}>{new Date(d.last_call).toLocaleDateString('fr-CH')}</td>
                                            <td><button className="btn btn-secondary btn-sm" onClick={async () => {
                                                await api.post('/my/contacts', { phone_number: d.phone_number, name: d.name || '' });
                                                notify.success('Ajouté aux contacts'); load();
                                            }}>+ Contact</button></td>
                                        </tr>
                                    ))}
                                </tbody>
                            </table>
                        )}
                    </div>
                )}
            </div>
        </>
    );
};

const ContactEditCard = ({ contact, onSaved, onBack }) => {
    const { notify } = useApp();
    const [form, setForm] = useState({ ...contact });
    useEffect(() => setForm({ ...contact }), [contact.id]);
    const save = async () => {
        try {
            await api.put(`/my/contacts/${contact.id}`, {
                name: form.name, company: form.company, email: form.email, notes: form.notes,
                is_vip: !!form.is_vip, is_blacklisted: !!form.is_blacklisted,
            });
            notify.success('Enregistré'); onSaved && onSaved();
        } catch (e) { notify.error('Erreur'); }
    };
    const remove = async () => {
        if (!confirm('Supprimer ce contact ?')) return;
        try { await api.del(`/my/contacts/${contact.id}`); notify.success('Supprimé'); onBack && onBack(); onSaved && onSaved(); }
        catch (e) { notify.error('Erreur'); }
    };
    return (
        <div className="card" style={{ padding: '1rem' }}>
            <h3 style={{ margin: '0 0 0.75rem' }}>Fiche contact</h3>
            <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                <div className="form-row"><label>Nom</label><input className="form-input" value={form.name || ''} onChange={e => setForm({ ...form, name: e.target.value })} /></div>
                <div className="form-row"><label>Société</label><input className="form-input" value={form.company || ''} onChange={e => setForm({ ...form, company: e.target.value })} /></div>
                <div className="form-row"><label>Email</label><input className="form-input" type="email" value={form.email || ''} onChange={e => setForm({ ...form, email: e.target.value })} /></div>
                <div className="form-row"><label>Notes</label><textarea className="form-input" rows={3} value={form.notes || ''} onChange={e => setForm({ ...form, notes: e.target.value })} /></div>
                <div style={{ display: 'flex', gap: '1rem' }}>
                    <label className="toggle-row"><input type="checkbox" checked={!!form.is_vip} onChange={e => setForm({ ...form, is_vip: e.target.checked })} /><span>VIP</span></label>
                    <label className="toggle-row"><input type="checkbox" checked={!!form.is_blacklisted} onChange={e => setForm({ ...form, is_blacklisted: e.target.checked })} /><span>Bloqué</span></label>
                </div>
                <div style={{ display: 'flex', gap: '0.5rem', marginTop: '0.5rem', flexWrap: 'wrap' }}>
                    <button className="btn btn-primary" onClick={save}>Enregistrer</button>
                    <button className="btn btn-secondary" onClick={remove}>Supprimer</button>
                    <PhoneHistoryButton phone={contact.phone_number} />
                </div>
            </div>
        </div>
    );
};

// ==================== PROXY NUMBERS VIEW ====================
const ProxyNumbersView = () => {
    const { notify } = useApp();
    const [items, setItems] = useState([]);
    const [lines, setLines] = useState([]);
    const [loading, setLoading] = useState(true);
    const [show, setShow] = useState(false);
    const [draft, setDraft] = useState({ line_id: '', target_number: '', label: '', expires_at: '', max_calls: '' });
    const load = async () => {
        setLoading(true);
        try {
            const [a, b] = await Promise.all([api.get('/my/proxy-numbers'), api.get('/my/lines')]);
            setItems(a?.proxy_numbers || []); setLines(b?.lines || []);
        } catch (e) { notify.error('Erreur'); } finally { setLoading(false); }
    };
    useEffect(() => { load(); }, []);
    const create = async () => {
        if (!draft.line_id || !draft.target_number) return notify.error('Ligne + cible requis');
        try {
            const r = await api.post('/my/proxy-numbers', {
                line_id: parseInt(draft.line_id),
                target_number: draft.target_number,
                label: draft.label || null,
                expires_at: draft.expires_at || null,
                max_calls: draft.max_calls ? parseInt(draft.max_calls) : null,
            });
            if (r?.error) return notify.error(r.error);
            notify.success('Créé'); setShow(false); setDraft({ line_id: '', target_number: '', label: '', expires_at: '', max_calls: '' }); load();
        } catch (e) { notify.error('Erreur: ' + e.message); }
    };
    const remove = async (p) => {
        if (!confirm(`Supprimer le numéro temporaire "${p.label || p.target_number}" ?`)) return;
        try { await api.del(`/my/proxy-numbers/${p.id}`); notify.success('Supprimé'); load(); }
        catch (e) { notify.error('Erreur'); }
    };
    const toggle = async (p) => {
        try { await api.put(`/my/proxy-numbers/${p.id}`, { is_active: !p.is_active ? 1 : 0 }); load(); }
        catch (e) { notify.error('Erreur'); }
    };
    return (
        <>
            <div className="page-header">
                <div><h1 className="page-title">Numéros temporaires</h1><p className="page-subtitle">Masquez votre vrai numéro derrière une de vos lignes Vocal (Anibis, Tutti, livraisons…)</p></div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={load}><Icons.Refresh className="w-4 h-4" /> Actualiser</button>
                    <button className="btn btn-primary btn-sm" onClick={() => setShow(true)}><Icons.Plus className="w-4 h-4" /> Nouveau</button>
                </div>
            </div>
            <div className="page-content">
                {show && (
                    <div className="card" style={{ padding: '1rem', marginBottom: '1rem', border: '2px solid var(--primary-light)' }}>
                        <h3 style={{ margin: '0 0 0.75rem' }}>Nouveau numéro temporaire</h3>
                        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem' }}>
                            <div className="form-row">
                                <label>Ligne Vocal qui sera affichée</label>
                                <select className="form-input" value={draft.line_id} onChange={e => setDraft({ ...draft, line_id: e.target.value })}>
                                    <option value="">- Choisir -</option>
                                    {lines.map(l => <option key={l.id} value={l.id}>{l.phone_number} {l.label ? `(${l.label})` : ''}</option>)}
                                </select>
                            </div>
                            <div className="form-row"><label>Vers (votre vrai numéro)</label><input className="form-input" value={draft.target_number} onChange={e => setDraft({ ...draft, target_number: e.target.value })} placeholder="+41 79 …" /></div>
                            <div className="form-row"><label>Étiquette</label><input className="form-input" value={draft.label} onChange={e => setDraft({ ...draft, label: e.target.value })} placeholder="Annonce Anibis Vespa 2018" /></div>
                            <div className="form-row"><label>Expire le (optionnel)</label><input type="datetime-local" className="form-input" value={draft.expires_at} onChange={e => setDraft({ ...draft, expires_at: e.target.value })} /></div>
                            <div className="form-row"><label>Limite d'appels (optionnel)</label><input type="number" className="form-input" value={draft.max_calls} onChange={e => setDraft({ ...draft, max_calls: e.target.value })} /></div>
                        </div>
                        <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end', marginTop: '0.75rem' }}>
                            <button className="btn btn-secondary" onClick={() => setShow(false)}>Annuler</button>
                            <button className="btn btn-primary" onClick={create}>Créer</button>
                        </div>
                    </div>
                )}
                {loading ? <p>Chargement…</p> : items.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>Aucun numéro temporaire.</p> : (
                    <div className="card">
                        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.875rem' }}>
                            <thead><tr style={{ background: '#f8fafc', textAlign: 'left' }}>
                                <th style={{ padding: '0.75rem 1rem' }}>Étiquette</th><th>Affichage</th><th>Vers</th><th>Appels</th><th>Expire</th><th>Actif</th><th></th>
                            </tr></thead>
                            <tbody>
                                {items.map(p => (
                                    <tr key={p.id} style={{ borderTop: '1px solid var(--border)' }}>
                                        <td style={{ padding: '0.6rem 1rem' }}>{p.label || '-'}</td>
                                        <td style={{ fontFamily: 'ui-monospace, monospace' }}>{p.proxy_phone_number}</td>
                                        <td style={{ fontFamily: 'ui-monospace, monospace', color: 'var(--text-muted)' }}>{p.target_number}</td>
                                        <td>{p.used_calls || 0}{p.max_calls ? ` / ${p.max_calls}` : ''}</td>
                                        <td style={{ color: 'var(--text-muted)' }}>{p.expires_at ? new Date(p.expires_at).toLocaleDateString('fr-CH') : '-'}</td>
                                        <td><input type="checkbox" checked={!!p.is_active} onChange={() => toggle(p)} /></td>
                                        <td><button className="btn btn-secondary btn-sm" onClick={() => remove(p)}><Icons.Trash className="w-4 h-4" /></button></td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>
                )}
            </div>
        </>
    );
};

// ==================== SPAM / BLACKLIST VIEW ====================
const SpamView = () => {
    const { notify } = useApp();
    const [reports, setReports] = useState([]);
    const [draft, setDraft] = useState({ phone_number: '', reason: 'robocall' });
    const [loading, setLoading] = useState(true);
    const load = async () => {
        setLoading(true);
        try { const r = await api.get('/my/spam-reports'); setReports(r?.reports || []); }
        catch (e) { notify.error('Erreur'); } finally { setLoading(false); }
    };
    useEffect(() => { load(); }, []);
    const report = async () => {
        if (!draft.phone_number.trim()) return notify.error('Numéro requis');
        try {
            const r = await api.post('/my/spam-reports', draft);
            if (r?.error) return notify.error(r.error);
            notify.success(`Signalé. Blacklisté chez ${r.distinct_clients || 1} client(s) Vocal.`);
            setDraft({ phone_number: '', reason: 'robocall' });
            load();
        } catch (e) { notify.error('Erreur: ' + e.message); }
    };
    return (
        <>
            <div className="page-header">
                <div><h1 className="page-title">Spam & blacklist</h1><p className="page-subtitle">Signalez en 1 clic les démarcheurs et robocalls. Les numéros signalés par 3+ clients sont automatiquement bloqués pour tous.</p></div>
            </div>
            <div className="page-content" style={{ display: 'grid', gridTemplateColumns: 'minmax(280px, 1fr) 2fr', gap: '1rem' }}>
                <div className="card" style={{ padding: '1rem' }}>
                    <h3 style={{ margin: '0 0 0.75rem' }}>Signaler un numéro</h3>
                    <div className="form-row"><label>Numéro</label><input className="form-input" value={draft.phone_number} onChange={e => setDraft({ ...draft, phone_number: e.target.value })} placeholder="+41 … ou 0…" /></div>
                    <div className="form-row"><label>Motif</label>
                        <select className="form-input" value={draft.reason} onChange={e => setDraft({ ...draft, reason: e.target.value })}>
                            <option value="robocall">Robocall</option>
                            <option value="phishing">Hameçonnage / arnaque</option>
                            <option value="commercial">Démarchage commercial</option>
                            <option value="other">Autre</option>
                        </select>
                    </div>
                    <button className="btn btn-primary" onClick={report} style={{ width: '100%', marginTop: '0.5rem' }}>
                        <Icons.AlertCircle className="w-4 h-4" /> Signaler & bloquer
                    </button>
                </div>
                <div className="card">
                    <div style={{ padding: '1rem 1.25rem', borderBottom: '1px solid var(--border)', fontWeight: 700 }}>Mes signalements</div>
                    {loading ? <p style={{ padding: '1rem' }}>Chargement…</p> : reports.length === 0 ? <p style={{ padding: '1rem', color: 'var(--text-muted)' }}>Aucun signalement.</p> : (
                        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.875rem' }}>
                            <thead><tr style={{ textAlign: 'left', color: 'var(--text-muted)' }}><th style={{ padding: '0.5rem 1rem' }}>Numéro</th><th>Motif</th><th>Date</th></tr></thead>
                            <tbody>
                                {reports.map(r => (
                                    <tr key={r.id} style={{ borderTop: '1px solid var(--border)' }}>
                                        <td style={{ padding: '0.5rem 1rem', fontFamily: 'ui-monospace, monospace' }}>{r.phone_number}</td>
                                        <td>{r.reason}</td>
                                        <td style={{ color: 'var(--text-muted)' }}>{new Date(r.created_at).toLocaleString('fr-CH')}</td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    )}
                </div>
            </div>
        </>
    );
};

// ==================== PORTING VIEW ====================
const PortingView = () => {
    const { notify } = useApp();
    const [reqs, setReqs] = useState([]);
    const [show, setShow] = useState(false);
    const [draft, setDraft] = useState({ phone_number: '', current_carrier: '', account_number: '', owner_name: '', owner_address: '', owner_email: '', desired_date: '', notes: '', documents_url: '' });
    const [loading, setLoading] = useState(true);
    const load = async () => {
        setLoading(true);
        try { const r = await api.get('/my/port-requests'); setReqs(r?.port_requests || []); }
        catch (e) { notify.error('Erreur'); } finally { setLoading(false); }
    };
    useEffect(() => { load(); }, []);
    const create = async () => {
        if (!draft.phone_number || !draft.owner_name) return notify.error('Numéro et titulaire requis');
        try {
            await api.post('/my/port-requests', draft);
            notify.success('Demande envoyée. Notre équipe vous contactera sous 48h.');
            setShow(false);
            setDraft({ phone_number: '', current_carrier: '', account_number: '', owner_name: '', owner_address: '', owner_email: '', desired_date: '', notes: '', documents_url: '' });
            load();
        } catch (e) { notify.error('Erreur: ' + e.message); }
    };
    const cancel = async (r) => {
        if (!confirm(`Annuler la demande pour ${r.phone_number} ?`)) return;
        try { await api.del(`/my/port-requests/${r.id}`); notify.success('Annulée'); load(); } catch (e) { notify.error('Erreur'); }
    };
    const statusBadge = (s) => {
        const map = { requested: ['#fef3c7', '#854d0e', 'En attente'], in_review: ['#dbeafe', '#1e40af', 'En revue'], submitted: ['#e0e7ff', '#4338ca', 'Envoyée à l\'opérateur'], completed: ['#dcfce7', '#15803d', 'Portée'], rejected: ['#fee2e2', '#b91c1c', 'Refusée'], cancelled: ['#f1f5f9', '#475569', 'Annulée'] };
        const [bg, fg, label] = map[s] || ['#f1f5f9', '#475569', s];
        return <span style={{ background: bg, color: fg, padding: '0.2rem 0.6rem', borderRadius: 999, fontSize: '0.75rem', fontWeight: 600 }}>{label}</span>;
    };
    return (
        <>
            <div className="page-header">
                <div><h1 className="page-title">Portabilité</h1><p className="page-subtitle">Transférez votre numéro existant (Swisscom, Sunrise, Salt…) vers Vocal sans perdre vos appels.</p></div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={load}><Icons.Refresh className="w-4 h-4" /> Actualiser</button>
                    <button className="btn btn-primary btn-sm" onClick={() => setShow(true)}><Icons.Plus className="w-4 h-4" /> Nouvelle demande</button>
                </div>
            </div>
            <div className="page-content">
                <div className="card" style={{ padding: '1rem 1.25rem', marginBottom: '1rem', background: '#eef2ff', border: '1px solid #c7d2fe', fontSize: '0.875rem', color: '#3730a3' }}>
                    <strong>Comment ça marche :</strong> remplissez le formulaire avec les infos exactes du contrat actuel, joignez (URL) une copie d'identité + un mandat signé. Notre équipe traite la demande sous 48h ouvrées et vous tient informé. Le portage prend généralement 2 à 4 semaines selon l'opérateur de départ.
                </div>
                {show && (
                    <div className="card" style={{ padding: '1rem', marginBottom: '1rem', border: '2px solid var(--primary-light)' }}>
                        <h3 style={{ margin: '0 0 0.75rem' }}>Nouvelle demande de portabilité</h3>
                        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem' }}>
                            <div className="form-row"><label>Numéro à porter *</label><input className="form-input" value={draft.phone_number} onChange={e => setDraft({ ...draft, phone_number: e.target.value })} placeholder="+41 22 …" /></div>
                            <div className="form-row"><label>Opérateur actuel</label>
                                <select className="form-input" value={draft.current_carrier} onChange={e => setDraft({ ...draft, current_carrier: e.target.value })}>
                                    <option value="">- Choisir -</option><option>Swisscom</option><option>Sunrise</option><option>Salt</option><option>Wingo</option><option>Yallo</option><option>Lebara</option><option>Coop Mobile</option><option>M-Budget</option><option>Autre</option>
                                </select>
                            </div>
                            <div className="form-row"><label>N° de contrat / compte chez l'opérateur</label><input className="form-input" value={draft.account_number} onChange={e => setDraft({ ...draft, account_number: e.target.value })} /></div>
                            <div className="form-row"><label>Titulaire (exact contrat) *</label><input className="form-input" value={draft.owner_name} onChange={e => setDraft({ ...draft, owner_name: e.target.value })} /></div>
                            <div className="form-row" style={{ gridColumn: '1 / -1' }}><label>Adresse facturation</label><input className="form-input" value={draft.owner_address} onChange={e => setDraft({ ...draft, owner_address: e.target.value })} /></div>
                            <div className="form-row"><label>Email de contact</label><input className="form-input" type="email" value={draft.owner_email} onChange={e => setDraft({ ...draft, owner_email: e.target.value })} /></div>
                            <div className="form-row"><label>Date de portage souhaitée</label><input className="form-input" type="date" value={draft.desired_date} onChange={e => setDraft({ ...draft, desired_date: e.target.value })} /></div>
                            <div className="form-row" style={{ gridColumn: '1 / -1' }}><label>Documents (URL d'un dossier partagé contenant identité + mandat signé)</label><input className="form-input" value={draft.documents_url} onChange={e => setDraft({ ...draft, documents_url: e.target.value })} placeholder="https://drive.google.com/…" /></div>
                            <div className="form-row" style={{ gridColumn: '1 / -1' }}><label>Notes</label><textarea className="form-input" rows={2} value={draft.notes} onChange={e => setDraft({ ...draft, notes: e.target.value })} /></div>
                        </div>
                        <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end', marginTop: '0.75rem' }}>
                            <button className="btn btn-secondary" onClick={() => setShow(false)}>Annuler</button>
                            <button className="btn btn-primary" onClick={create}>Envoyer</button>
                        </div>
                    </div>
                )}
                {loading ? <p>Chargement…</p> : reqs.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>Aucune demande.</p> : (
                    <div className="card">
                        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.875rem' }}>
                            <thead><tr style={{ background: '#f8fafc', textAlign: 'left' }}>
                                <th style={{ padding: '0.75rem 1rem' }}>Numéro</th><th>Opérateur</th><th>Titulaire</th><th>Statut</th><th>Date</th><th></th>
                            </tr></thead>
                            <tbody>
                                {reqs.map(r => (
                                    <tr key={r.id} style={{ borderTop: '1px solid var(--border)' }}>
                                        <td style={{ padding: '0.6rem 1rem', fontFamily: 'ui-monospace, monospace' }}>{r.phone_number}</td>
                                        <td>{r.current_carrier || '-'}</td>
                                        <td>{r.owner_name}</td>
                                        <td>{statusBadge(r.status)}</td>
                                        <td style={{ color: 'var(--text-muted)' }}>{new Date(r.created_at).toLocaleDateString('fr-CH')}</td>
                                        <td>{['requested', 'in_review'].includes(r.status) && <button className="btn btn-secondary btn-sm" onClick={() => cancel(r)}>Annuler</button>}</td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>
                )}
            </div>
        </>
    );
};

// ==================== PHONE HISTORY (modal + provider + helpers) ====================
const PhoneHistoryContext = createContext({ open: () => {} });
const usePhoneHistory = () => useContext(PhoneHistoryContext);

const PhoneHistoryProvider = ({ children }) => {
    const [phone, setPhone] = useState(null);
    const open = useCallback((p) => { if (p) setPhone(p); }, []);
    return (
        <PhoneHistoryContext.Provider value={{ open }}>
            {children}
            {phone && <PhoneHistoryModal phone={phone} onClose={() => setPhone(null)} />}
        </PhoneHistoryContext.Provider>
    );
};

const PhoneLink = ({ phone, children, style }) => {
    const { open } = usePhoneHistory();
    if (!phone) return <span>{children || '-'}</span>;
    return (
        <button
            type="button"
            onClick={(e) => { e.stopPropagation(); open(phone); }}
            style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer', color: 'var(--primary)', font: 'inherit', textAlign: 'left', textDecoration: 'underline dotted', ...(style || {}) }}
            title={phone}
        >
            {children != null ? children : phone}
        </button>
    );
};

const PhoneHistoryButton = ({ phone, label }) => {
    const { open } = usePhoneHistory();
    const lang = useLang();
    if (!phone) return null;
    return (
        <button type="button" className="btn btn-secondary btn-sm" onClick={() => open(phone)}>
            <Icons.Eye className="w-4 h-4" /> {label || (lang === 'de' ? 'Verlauf' : lang === 'en' ? 'History' : lang === 'it' ? 'Storico' : "Voir l'historique")}
        </button>
    );
};

const PhoneHistoryModal = ({ phone, onClose }) => {
    const { notify } = useApp();
    const lang = useLang();
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [tab, setTab] = useState('calls');
    const [busy, setBusy] = useState(false);

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const r = await api.get(`/my/phone-history/${encodeURIComponent(phone)}`);
            if (r?.error) notify.error(r.error);
            setData(r || {});
        } catch (e) { notify.error('Erreur chargement'); }
        finally { setLoading(false); }
    }, [phone, notify]);

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

    const blockNumber = async () => {
        if (!confirm(`Bloquer ${phone} ?`)) return;
        setBusy(true);
        try {
            const r = await api.post('/my/spam-reports', { phone_number: phone, reason: 'other' });
            if (r?.error) notify.error(r.error);
            else { notify.success('Numéro bloqué'); load(); }
        } catch (e) { notify.error('Erreur: ' + e.message); }
        finally { setBusy(false); }
    };

    const enriched = data?.enriched;
    const contact = data?.contact;
    const calls = data?.calls || [];
    const sms = data?.sms || [];
    const conversations = data?.conversations || [];
    const nps = data?.nps || [];
    const spamReports = data?.spam_reports || [];

    const tabs = [
        { id: 'calls', label: t('nav.calls', lang) + ` (${calls.length})` },
        { id: 'sms', label: 'SMS' + ` (${sms.length})` },
        { id: 'conv', label: t('nav.conversations', lang) + ` (${conversations.length})` },
        { id: 'nps', label: 'NPS' + ` (${nps.length})` },
        { id: 'spam', label: 'Spam' + ` (${spamReports.length})` },
    ];

    return (
        <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.45)', zIndex: 200, display: 'flex', alignItems: 'flex-start', justifyContent: 'center', padding: '2rem 1rem', overflowY: 'auto' }}>
            <div onClick={(e) => e.stopPropagation()} className="card" style={{ background: 'var(--bg-white)', width: '100%', maxWidth: 880, padding: 0, boxShadow: '0 24px 64px rgba(0,0,0,0.25)' }}>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '1rem 1.25rem', borderBottom: '1px solid var(--border)' }}>
                    <div>
                        <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.05em', fontWeight: 600 }}>{t('nav.contacts', lang)}</div>
                        <h2 style={{ margin: 0, fontFamily: 'ui-monospace, monospace', fontSize: '1.15rem' }}>{phone}</h2>
                    </div>
                    <div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
                        <button className="btn btn-secondary btn-sm" onClick={blockNumber} disabled={busy}>
                            <Icons.Shield className="w-4 h-4" /> Bloquer
                        </button>
                        <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '0.5rem' }} title={t('common.cancel', lang)}>
                            <Icons.X className="w-5 h-5" />
                        </button>
                    </div>
                </div>

                <div style={{ padding: '1rem 1.25rem' }}>
                    {loading ? (
                        <p style={{ color: 'var(--text-muted)' }}>{t('common.loading', lang)}</p>
                    ) : (
                        <>
                            {(enriched || contact) && (
                                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: '0.75rem', marginBottom: '1rem' }}>
                                    {enriched && (
                                        <div className="card" style={{ padding: '0.75rem 1rem', background: '#f0f9ff', border: '1px solid #bae6fd' }}>
                                            <div style={{ fontSize: '0.7rem', textTransform: 'uppercase', color: '#0c4a6e', fontWeight: 700 }}>Enrichissement</div>
                                            <div style={{ fontWeight: 600, marginTop: '0.25rem' }}>{enriched.display_name || enriched.company_name || '-'}</div>
                                            {enriched.company_name && enriched.display_name && <div style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>{enriched.company_name}</div>}
                                            <div style={{ fontSize: '0.7rem', color: 'var(--text-muted)', marginTop: '0.4rem' }}>
                                                {enriched.source ? `Source : ${enriched.source}` : ''}
                                                {enriched.confidence != null ? ` · ${Math.round(Number(enriched.confidence) * 100)}%` : ''}
                                            </div>
                                        </div>
                                    )}
                                    {contact && (
                                        <div className="card" style={{ padding: '0.75rem 1rem' }}>
                                            <div style={{ fontSize: '0.7rem', textTransform: 'uppercase', color: 'var(--text-muted)', fontWeight: 700 }}>Fiche CRM</div>
                                            <div style={{ fontWeight: 600, marginTop: '0.25rem', display: 'flex', gap: '0.4rem', alignItems: 'center' }}>
                                                {contact.is_vip && <span title="VIP" style={{ color: '#f59e0b' }}>★</span>}
                                                {contact.is_blacklisted && <span title="Blacklisté" style={{ color: '#dc2626' }}>⊘</span>}
                                                {contact.name || '-'}
                                            </div>
                                            {contact.company && <div style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>{contact.company}</div>}
                                            {contact.email && <div style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>{contact.email}</div>}
                                            {contact.tags && <div style={{ fontSize: '0.7rem', color: 'var(--text-muted)', marginTop: '0.3rem' }}>{contact.tags}</div>}
                                            {contact.notes && <div style={{ fontSize: '0.75rem', marginTop: '0.4rem', color: '#475569', fontStyle: 'italic' }}>{contact.notes}</div>}
                                        </div>
                                    )}
                                </div>
                            )}

                            <div style={{ display: 'flex', gap: '0.25rem', borderBottom: '1px solid var(--border)', marginBottom: '0.75rem', overflowX: 'auto' }}>
                                {tabs.map(tt => (
                                    <button key={tt.id} onClick={() => setTab(tt.id)}
                                        style={{ background: 'none', border: 'none', padding: '0.5rem 0.85rem', cursor: 'pointer', fontSize: '0.8rem', fontWeight: 500, color: tab === tt.id ? 'var(--primary)' : 'var(--text-muted)', borderBottom: tab === tt.id ? '2px solid var(--primary)' : '2px solid transparent', whiteSpace: 'nowrap' }}>
                                        {tt.label}
                                    </button>
                                ))}
                            </div>

                            <div style={{ maxHeight: '50vh', overflow: 'auto' }}>
                                {tab === 'calls' && (
                                    calls.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>{t('common.empty', lang)}</p> : (
                                        <table style={{ width: '100%', fontSize: '0.85rem', borderCollapse: 'collapse' }}>
                                            <thead><tr style={{ textAlign: 'left', color: 'var(--text-muted)' }}><th style={{ padding: '0.4rem 0.5rem' }}>Date</th><th>Durée</th><th>Statut</th><th>Résumé</th></tr></thead>
                                            <tbody>{calls.map(c => (
                                                <tr key={c.id} style={{ borderTop: '1px solid var(--border)' }}>
                                                    <td style={{ padding: '0.4rem 0.5rem', whiteSpace: 'nowrap' }}>{formatDateTime(c.created_at)}</td>
                                                    <td style={{ whiteSpace: 'nowrap' }}>{formatDuration(c.duration)}</td>
                                                    <td>{c.status}</td>
                                                    <td style={{ color: '#475569', fontStyle: 'italic' }}>{c.ai_summary || c.transcript ? <span title={c.transcript || ''}>{(c.ai_summary || '').slice(0, 120)}</span> : '-'}</td>
                                                </tr>
                                            ))}</tbody>
                                        </table>
                                    )
                                )}
                                {tab === 'sms' && (
                                    sms.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>{t('common.empty', lang)}</p> : (
                                        <table style={{ width: '100%', fontSize: '0.85rem', borderCollapse: 'collapse' }}>
                                            <thead><tr style={{ textAlign: 'left', color: 'var(--text-muted)' }}><th style={{ padding: '0.4rem 0.5rem' }}>Date</th><th>Sens</th><th>Message</th></tr></thead>
                                            <tbody>{sms.map(m => (
                                                <tr key={m.id} style={{ borderTop: '1px solid var(--border)' }}>
                                                    <td style={{ padding: '0.4rem 0.5rem', whiteSpace: 'nowrap' }}>{formatDateTime(m.created_at)}</td>
                                                    <td>{m.direction === 'outbound' ? '↑' : '↓'}</td>
                                                    <td>{m.body}</td>
                                                </tr>
                                            ))}</tbody>
                                        </table>
                                    )
                                )}
                                {tab === 'conv' && (
                                    conversations.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>{t('common.empty', lang)}</p> : (
                                        <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>{conversations.map(c => (
                                            <li key={c.id} style={{ padding: '0.5rem 0', borderTop: '1px solid var(--border)', fontSize: '0.85rem' }}>
                                                <strong>{c.channel}</strong> · <span style={{ color: 'var(--text-muted)' }}>{formatRelative(c.last_message_at)}</span>
                                                <div>{c.last_message_preview}</div>
                                            </li>
                                        ))}</ul>
                                    )
                                )}
                                {tab === 'nps' && (
                                    nps.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>{t('common.empty', lang)}</p> : (
                                        <table style={{ width: '100%', fontSize: '0.85rem', borderCollapse: 'collapse' }}>
                                            <thead><tr style={{ textAlign: 'left', color: 'var(--text-muted)' }}><th style={{ padding: '0.4rem 0.5rem' }}>Date</th><th>Score</th><th>Méthode</th><th>Comment</th></tr></thead>
                                            <tbody>{nps.map(n => (
                                                <tr key={n.id} style={{ borderTop: '1px solid var(--border)' }}>
                                                    <td style={{ padding: '0.4rem 0.5rem' }}>{formatDateTime(n.created_at)}</td>
                                                    <td><strong>{n.score ?? '-'}</strong></td>
                                                    <td>{n.method}</td>
                                                    <td style={{ color: '#475569' }}>{n.comment || '-'}</td>
                                                </tr>
                                            ))}</tbody>
                                        </table>
                                    )
                                )}
                                {tab === 'spam' && (
                                    spamReports.length === 0 ? <p style={{ color: 'var(--text-muted)' }}>{t('common.empty', lang)}</p> : (
                                        <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>{spamReports.map(r => (
                                            <li key={r.id} style={{ padding: '0.5rem 0', borderTop: '1px solid var(--border)', fontSize: '0.85rem' }}>
                                                <strong>{r.reason}</strong> · <span style={{ color: 'var(--text-muted)' }}>{formatDateTime(r.created_at)}</span>
                                            </li>
                                        ))}</ul>
                                    )
                                )}
                            </div>
                        </>
                    )}
                </div>
            </div>
        </div>
    );
};

// ==================== CONVERSATIONS VIEW ====================
const ConversationsView = () => {
    const { notify } = useApp();
    const lang = useLang();
    const [list, setList] = useState([]);
    const [loading, setLoading] = useState(true);
    const [refreshing, setRefreshing] = useState(false);
    const [channel, setChannel] = useState('');
    const [openId, setOpenId] = useState(null);

    const load = useCallback(async (background = false) => {
        if (background) setRefreshing(true); else setLoading(true);
        try {
            const params = new URLSearchParams();
            if (channel) params.set('channel', channel);
            const r = await api.get(`/my/conversations?${params}`);
            setList(r?.conversations || []);
        } catch (e) { notify.error('Erreur'); }
        finally { setLoading(false); setRefreshing(false); }
    }, [channel, notify]);

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

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">{t('nav.conversations', lang)}</h1>
                    <p className="page-subtitle">WhatsApp · Webchat · SMS - historique unifié par contact.</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={() => load(true)} disabled={refreshing}>
                        <Icons.Refresh className="w-4 h-4" /> {refreshing ? '…' : 'Actualiser'}
                    </button>
                </div>
            </div>
            <div className="page-content">
                <div className="card">
                    <div style={{ padding: '1rem 1.25rem', borderBottom: '1px solid var(--border)', display: 'flex', gap: '0.5rem', flexWrap: 'wrap', alignItems: 'center' }}>
                        <select className="form-input" value={channel} onChange={e => setChannel(e.target.value)} style={{ width: 200, marginBottom: 0 }}>
                            <option value="">Tous les canaux</option>
                            <option value="whatsapp">WhatsApp</option>
                            <option value="webchat">Webchat</option>
                            <option value="sms">SMS</option>
                        </select>
                    </div>
                    {loading ? (
                        <p style={{ padding: '1rem' }}>{t('common.loading', lang)}</p>
                    ) : list.length === 0 ? (
                        <p style={{ padding: '2rem', color: 'var(--text-muted)', textAlign: 'center' }}>{t('common.empty', lang)}</p>
                    ) : (
                        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.875rem' }}>
                            <thead><tr style={{ background: '#f8fafc', textAlign: 'left' }}>
                                <th style={{ padding: '0.65rem 1rem' }}>Contact</th>
                                <th>Canal</th>
                                <th>Dernier message</th>
                                <th>Quand</th>
                                <th style={{ textAlign: 'right' }}>Non lus</th>
                            </tr></thead>
                            <tbody>{list.map(c => (
                                <tr key={c.id} style={{ borderTop: '1px solid var(--border)', cursor: 'pointer' }} onClick={() => setOpenId(c.id)}>
                                    <td style={{ padding: '0.6rem 1rem' }}>
                                        <div style={{ fontWeight: 600 }}>{c.contact_name || '-'}</div>
                                        <div style={{ fontFamily: 'ui-monospace, monospace', fontSize: '0.75rem', color: 'var(--text-muted)' }}>
                                            <PhoneLink phone={c.contact_phone}>{c.contact_phone}</PhoneLink>
                                        </div>
                                    </td>
                                    <td><span className="badge badge-info" style={{ textTransform: 'capitalize' }}>{c.channel}</span></td>
                                    <td style={{ color: '#475569', maxWidth: 380, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.last_message_preview || '-'}</td>
                                    <td style={{ color: 'var(--text-muted)', whiteSpace: 'nowrap' }}>{formatRelative(c.last_message_at)}</td>
                                    <td style={{ textAlign: 'right' }}>{c.unread_count > 0 ? <span className="badge badge-primary">{c.unread_count}</span> : <span style={{ color: 'var(--text-muted)' }}>-</span>}</td>
                                </tr>
                            ))}</tbody>
                        </table>
                    )}
                </div>
            </div>
            {openId && <ConversationDetailModal id={openId} onClose={() => { setOpenId(null); load(true); }} />}
        </>
    );
};

const ConversationDetailModal = ({ id, onClose }) => {
    const { notify } = useApp();
    const lang = useLang();
    const [conv, setConv] = useState(null);
    const [messages, setMessages] = useState([]);
    const [body, setBody] = useState('');
    const [sending, setSending] = useState(false);
    const scrollRef = useRef(null);

    const load = useCallback(async (background = false) => {
        try {
            const r = await api.get(`/my/conversations/${id}`);
            if (r?.error) { notify.error(r.error); return; }
            setConv(r.conversation || null);
            setMessages(r.messages || []);
        } catch (e) { if (!background) notify.error('Erreur'); }
    }, [id, notify]);

    useEffect(() => { load(); }, [load]);
    useEffect(() => {
        const i = setInterval(() => load(true), 4000);
        return () => clearInterval(i);
    }, [load]);
    useEffect(() => {
        if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
    }, [messages.length]);

    const send = async () => {
        if (!body.trim()) return;
        setSending(true);
        try {
            const r = await api.post('/my/conversations/send', { conversation_id: id, body: body.trim() });
            if (r?.error) notify.error(r.error);
            else { setBody(''); load(true); }
        } catch (e) { notify.error('Erreur: ' + e.message); }
        finally { setSending(false); }
    };

    return (
        <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.45)', zIndex: 200, display: 'flex', alignItems: 'flex-start', justifyContent: 'center', padding: '2rem 1rem', overflowY: 'auto' }}>
            <div onClick={(e) => e.stopPropagation()} className="card" style={{ background: 'var(--bg-white)', width: '100%', maxWidth: 720, padding: 0, display: 'flex', flexDirection: 'column', height: '80vh' }}>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0.75rem 1.25rem', borderBottom: '1px solid var(--border)' }}>
                    <div>
                        <div style={{ fontWeight: 700 }}>{conv?.contact_name || conv?.contact_phone || '-'}</div>
                        <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>
                            {conv?.channel} · <PhoneLink phone={conv?.contact_phone}>{conv?.contact_phone}</PhoneLink>
                        </div>
                    </div>
                    <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '0.5rem' }}><Icons.X className="w-5 h-5" /></button>
                </div>
                <div ref={scrollRef} style={{ flex: 1, overflowY: 'auto', padding: '1rem', background: '#f8fafc', display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                    {messages.length === 0 ? (
                        <p style={{ color: 'var(--text-muted)', textAlign: 'center' }}>{t('common.empty', lang)}</p>
                    ) : messages.map(m => {
                        const out = m.direction === 'outbound';
                        return (
                            <div key={m.id} style={{ alignSelf: out ? 'flex-end' : 'flex-start', maxWidth: '75%' }}>
                                <div style={{ background: out ? 'var(--primary)' : '#fff', color: out ? '#fff' : '#0f172a', padding: '0.55rem 0.85rem', borderRadius: 14, fontSize: '0.875rem', boxShadow: '0 1px 2px rgba(0,0,0,0.08)' }}>
                                    {m.body}
                                </div>
                                <div style={{ fontSize: '0.65rem', color: 'var(--text-muted)', marginTop: '0.2rem', textAlign: out ? 'right' : 'left' }}>
                                    {formatTimeOnly(m.created_at)}
                                </div>
                            </div>
                        );
                    })}
                </div>
                <div style={{ display: 'flex', gap: '0.5rem', padding: '0.75rem', borderTop: '1px solid var(--border)' }}>
                    <input className="form-input" value={body} onChange={e => setBody(e.target.value)}
                        onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } }}
                        placeholder="Écrire un message…" style={{ marginBottom: 0, flex: 1 }} />
                    <button className="btn btn-primary" onClick={send} disabled={sending || !body.trim()}>
                        <Icons.Send className="w-4 h-4" /> Envoyer
                    </button>
                </div>
            </div>
        </div>
    );
};

// ==================== ROUTING PANEL (line tab) ====================
const RoutingPanel = ({ lineId }) => {
    const { notify } = useApp();
    const lang = useLang();
    const [rules, setRules] = useState([]);
    const [loading, setLoading] = useState(true);
    const [draft, setDraft] = useState(null);

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const r = await api.get(`/my/lines/${lineId}/routing`);
            setRules(r?.rules || []);
        } catch (e) { notify.error('Erreur'); }
        finally { setLoading(false); }
    }, [lineId, notify]);

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

    const blank = () => ({
        id: null,
        label: '',
        priority: 100,
        is_active: true,
        match_type: 'caller_pattern',
        match_value: '',
        match_keywords: '',
        action_type: 'forward',
        action_target: '',
        action_message: '',
    });

    const startNew = () => setDraft(blank());
    const startEdit = (r) => setDraft({
        id: r.id,
        label: r.label || '',
        priority: r.priority ?? 100,
        is_active: !!r.is_active,
        match_type: r.match_type || 'caller_pattern',
        match_value: r.match_value || '',
        match_keywords: Array.isArray(r.match_keywords) ? r.match_keywords.join(', ') : (r.match_keywords || ''),
        action_type: r.action_type || 'forward',
        action_target: r.action_target || '',
        action_message: r.action_message || '',
    });

    const save = async () => {
        if (!draft.label.trim()) return notify.error('Libellé requis');
        const payload = {
            label: draft.label.trim(),
            priority: Number(draft.priority) || 100,
            is_active: !!draft.is_active,
            match_type: draft.match_type,
            match_value: draft.match_value || null,
            match_keywords: draft.match_type === 'keyword'
                ? (draft.match_keywords || '').split(',').map(s => s.trim()).filter(Boolean)
                : null,
            action_type: draft.action_type,
            action_target: draft.action_target || null,
            action_message: draft.action_message || null,
        };
        try {
            const r = draft.id
                ? await api.put(`/my/lines/${lineId}/routing/${draft.id}`, payload)
                : await api.post(`/my/lines/${lineId}/routing`, payload);
            if (r?.error) return notify.error(r.error);
            notify.success('Règle enregistrée');
            setDraft(null);
            load();
        } catch (e) { notify.error('Erreur: ' + e.message); }
    };

    const remove = async (r) => {
        if (!confirm(`Supprimer la règle "${r.label}" ?`)) return;
        try {
            const x = await api.del(`/my/lines/${lineId}/routing/${r.id}`);
            if (x?.error) notify.error(x.error);
            else { notify.success('Supprimée'); load(); }
        } catch (e) { notify.error('Erreur'); }
    };

    return (
        <div className="card" style={{ padding: '1.25rem' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1rem' }}>
                <h3 style={{ margin: 0 }}>{t('nav.routing', lang)}</h3>
                <button className="btn btn-primary btn-sm" onClick={startNew}><Icons.Plus className="w-4 h-4" /> Ajouter une règle</button>
            </div>
            <p style={{ margin: '0 0 1rem', color: 'var(--text-muted)', fontSize: '0.85rem' }}>
                Définissez des règles pour rediriger, filtrer ou personnaliser les appels en fonction du numéro appelant, de l'heure, d'un mot-clé ou d'une intention détectée.
            </p>

            {draft && (
                <div className="card" style={{ padding: '1rem', marginBottom: '1rem', border: '2px solid var(--primary-light)' }}>
                    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '0.75rem' }}>
                        <div className="form-row"><label>Libellé</label><input className="form-input" value={draft.label} onChange={e => setDraft({ ...draft, label: e.target.value })} /></div>
                        <div className="form-row"><label>Priorité</label><input type="number" className="form-input" value={draft.priority} onChange={e => setDraft({ ...draft, priority: e.target.value })} /></div>
                        <div className="form-row" style={{ gridColumn: '1 / -1' }}>
                            <label className="toggle-row"><input type="checkbox" checked={draft.is_active} onChange={e => setDraft({ ...draft, is_active: e.target.checked })} /><span>Active</span></label>
                        </div>
                        <div className="form-row"><label>Type de match</label>
                            <select className="form-input" value={draft.match_type} onChange={e => setDraft({ ...draft, match_type: e.target.value })}>
                                <option value="caller_pattern">Numéro appelant (regex)</option>
                                <option value="time">Plage horaire</option>
                                <option value="keyword">Mots-clés (transcription)</option>
                                <option value="intent">Intention</option>
                            </select>
                        </div>
                        {draft.match_type !== 'keyword' && (
                            <div className="form-row"><label>Valeur</label>
                                <input className="form-input" value={draft.match_value} onChange={e => setDraft({ ...draft, match_value: e.target.value })}
                                    placeholder={draft.match_type === 'caller_pattern' ? '^\\+4179.*' : draft.match_type === 'time' ? '08:00-17:00' : 'rendez-vous'} />
                            </div>
                        )}
                        {draft.match_type === 'keyword' && (
                            <div className="form-row" style={{ gridColumn: '1 / -1' }}>
                                <label>Mots-clés (séparés par virgules)</label>
                                <textarea className="form-input" rows={2} value={draft.match_keywords} onChange={e => setDraft({ ...draft, match_keywords: e.target.value })} placeholder="urgence, rendez-vous, devis" />
                            </div>
                        )}
                        <div className="form-row"><label>Action</label>
                            <select className="form-input" value={draft.action_type} onChange={e => setDraft({ ...draft, action_type: e.target.value })}>
                                <option value="forward">Rediriger</option>
                                <option value="voicemail">Messagerie</option>
                                <option value="sms">Envoyer un SMS</option>
                                <option value="hangup">Raccrocher</option>
                            </select>
                        </div>
                        <div className="form-row"><label>Cible</label>
                            <input className="form-input" value={draft.action_target} onChange={e => setDraft({ ...draft, action_target: e.target.value })}
                                placeholder={draft.action_type === 'forward' ? '+41 …' : ''} />
                        </div>
                        <div className="form-row" style={{ gridColumn: '1 / -1' }}>
                            <label>Message TTS (optionnel)</label>
                            <textarea className="form-input" rows={2} value={draft.action_message} onChange={e => setDraft({ ...draft, action_message: e.target.value })} />
                        </div>
                    </div>
                    <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end', marginTop: '0.75rem' }}>
                        <button className="btn btn-secondary" onClick={() => setDraft(null)}>{t('common.cancel', lang)}</button>
                        <button className="btn btn-primary" onClick={save}>{t('common.save', lang)}</button>
                    </div>
                </div>
            )}

            {loading ? <p>{t('common.loading', lang)}</p> : rules.length === 0 ? (
                <p style={{ color: 'var(--text-muted)' }}>{t('common.empty', lang)}</p>
            ) : (
                <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                    {rules.map(r => (
                        <div key={r.id} className="card" style={{ padding: '0.75rem 1rem', display: 'flex', alignItems: 'center', gap: '1rem', border: '1px solid var(--border)' }}>
                            <div style={{ flex: 1 }}>
                                <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', flexWrap: 'wrap' }}>
                                    <strong>{r.label}</strong>
                                    {r.is_active ? <span className="badge badge-success">Active</span> : <span className="badge badge-gray">Inactive</span>}
                                    <span className="badge badge-gray">Prio {r.priority}</span>
                                </div>
                                <div style={{ fontSize: '0.8rem', color: 'var(--text-muted)', marginTop: '0.25rem' }}>
                                    Si <strong>{r.match_type}</strong>{r.match_value ? <> = <code>{r.match_value}</code></> : null}
                                    {' → '}
                                    <strong>{r.action_type}</strong>{r.action_target ? <> ({r.action_target})</> : null}
                                </div>
                            </div>
                            <button className="btn btn-secondary btn-sm" onClick={() => startEdit(r)}><Icons.Edit className="w-4 h-4" /></button>
                            <button className="btn btn-secondary btn-sm" onClick={() => remove(r)} style={{ color: '#dc2626' }}><Icons.Trash className="w-4 h-4" /></button>
                        </div>
                    ))}
                </div>
            )}
        </div>
    );
};

// ==================== NPS PANEL (line tab) ====================
const NpsPanel = ({ line, onSaved }) => {
    const { notify } = useApp();
    const lang = useLang();
    const [form, setForm] = useState({
        nps_enabled: !!line.nps_enabled,
        nps_method: line.nps_method || 'dtmf',
        nps_question: line.nps_question || 'Comment évaluez-vous cet appel sur une échelle de 1 à 5 ?',
        nps_min_duration: line.nps_min_duration || 30,
    });
    const [saving, setSaving] = useState(false);
    const [surveys, setSurveys] = useState([]);
    const [loadingS, setLoadingS] = useState(true);

    useEffect(() => {
        setForm({
            nps_enabled: !!line.nps_enabled,
            nps_method: line.nps_method || 'dtmf',
            nps_question: line.nps_question || 'Comment évaluez-vous cet appel sur une échelle de 1 à 5 ?',
            nps_min_duration: line.nps_min_duration || 30,
        });
    }, [line.id]);

    const load = useCallback(async () => {
        setLoadingS(true);
        try {
            const r = await api.get(`/my/nps/surveys?line_id=${line.id}`);
            setSurveys(r?.surveys || []);
        } catch (e) {} finally { setLoadingS(false); }
    }, [line.id]);

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

    const save = async () => {
        setSaving(true);
        try {
            const r = await api.put(`/my/lines/${line.id}/nps`, {
                nps_enabled: !!form.nps_enabled,
                nps_method: form.nps_method,
                nps_question: form.nps_question,
                nps_min_duration: Number(form.nps_min_duration) || 30,
            });
            if (r?.error) notify.error(r.error);
            else { notify.success('Configuration NPS enregistrée'); onSaved?.(); }
        } catch (e) { notify.error('Erreur: ' + e.message); }
        finally { setSaving(false); }
    };

    const stats = useMemo(() => npsAggregate(surveys), [surveys]);

    return (
        <>
            <div className="card" style={{ padding: '1.5rem', marginBottom: '1rem' }}>
                <h3 style={{ margin: '0 0 1rem' }}>{t('nav.nps', lang)} - Configuration</h3>
                <div className="form-group">
                    <label className="toggle-row"><input type="checkbox" checked={form.nps_enabled} onChange={e => setForm({ ...form, nps_enabled: e.target.checked })} /><span>Activer le sondage NPS après les appels</span></label>
                </div>
                <div className="form-group">
                    <label className="form-label">Méthode</label>
                    <select className="form-input" value={form.nps_method} onChange={e => setForm({ ...form, nps_method: e.target.value })}>
                        <option value="dtmf">Touches DTMF (1-5)</option>
                        <option value="voice">Réponse vocale</option>
                        <option value="sms">SMS post-appel</option>
                    </select>
                </div>
                <div className="form-group">
                    <label className="form-label">Question</label>
                    <textarea className="form-input" rows={2} value={form.nps_question} onChange={e => setForm({ ...form, nps_question: e.target.value })} />
                </div>
                <div className="form-group">
                    <label className="form-label">Durée minimale d'appel (secondes) avant déclenchement</label>
                    <input type="number" className="form-input" value={form.nps_min_duration} onChange={e => setForm({ ...form, nps_min_duration: e.target.value })} />
                </div>
                <button className="btn btn-primary" onClick={save} disabled={saving}>{saving ? '…' : t('common.save', lang)}</button>
            </div>

            <div className="card" style={{ padding: '1.25rem' }}>
                <h3 style={{ margin: '0 0 1rem' }}>Résultats récents</h3>
                {loadingS ? <p>{t('common.loading', lang)}</p> : (
                    <>
                        <div className="stats-grid" style={{ marginBottom: '1rem' }}>
                            <div className="stat-card"><div className="stat-icon blue"><Icons.Star className="w-6 h-6" /></div><div><div className="stat-label">Score moyen</div><div className="stat-value">{stats.avg.toFixed(2)}</div></div></div>
                            <div className="stat-card"><div className="stat-icon green"><Icons.Check className="w-6 h-6" /></div><div><div className="stat-label">Promoteurs (≥4)</div><div className="stat-value">{stats.promotersPct}%</div></div></div>
                            <div className="stat-card"><div className="stat-icon orange"><Icons.AlertCircle className="w-6 h-6" /></div><div><div className="stat-label">Détracteurs (≤2)</div><div className="stat-value">{stats.detractorsPct}%</div></div></div>
                            <div className="stat-card"><div className="stat-icon purple"><Icons.Sparkles className="w-6 h-6" /></div><div><div className="stat-label">NPS</div><div className="stat-value">{stats.nps}</div></div></div>
                        </div>
                        <NpsSurveysTable surveys={surveys} />
                    </>
                )}
            </div>
        </>
    );
};

function npsAggregate(surveys) {
    const valid = (surveys || []).filter(s => s.score != null && !Number.isNaN(Number(s.score)));
    const total = valid.length;
    if (total === 0) return { total: 0, avg: 0, promotersPct: 0, detractorsPct: 0, nps: 0 };
    const sum = valid.reduce((a, s) => a + Number(s.score), 0);
    const promoters = valid.filter(s => Number(s.score) >= 4).length;
    const detractors = valid.filter(s => Number(s.score) <= 2).length;
    const promotersPct = Math.round((promoters / total) * 100);
    const detractorsPct = Math.round((detractors / total) * 100);
    return {
        total,
        avg: sum / total,
        promotersPct,
        detractorsPct,
        nps: promotersPct - detractorsPct,
    };
}

const NpsSurveysTable = ({ surveys }) => {
    const lang = useLang();
    if (!surveys || surveys.length === 0) return <p style={{ color: 'var(--text-muted)' }}>{t('common.empty', lang)}</p>;
    return (
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.85rem' }}>
            <thead><tr style={{ background: '#f8fafc', textAlign: 'left' }}>
                <th style={{ padding: '0.5rem 0.75rem' }}>Date</th>
                <th>Numéro</th>
                <th>Score</th>
                <th>Méthode</th>
                <th>Commentaire</th>
            </tr></thead>
            <tbody>{surveys.slice(0, 50).map(s => (
                <tr key={s.id} style={{ borderTop: '1px solid var(--border)' }}>
                    <td style={{ padding: '0.45rem 0.75rem', whiteSpace: 'nowrap' }}>{formatDateTime(s.created_at)}</td>
                    <td style={{ fontFamily: 'ui-monospace, monospace' }}><PhoneLink phone={s.caller_number}>{s.caller_number || '-'}</PhoneLink></td>
                    <td><strong>{s.score ?? '-'}</strong></td>
                    <td>{s.method || '-'}</td>
                    <td style={{ color: '#475569' }}>{(s.comment || '').slice(0, 80)}{(s.comment || '').length > 80 ? '…' : ''}</td>
                </tr>
            ))}</tbody>
        </table>
    );
};

// ==================== NPS GLOBAL VIEW ====================
const NpsView = () => {
    const { notify } = useApp();
    const lang = useLang();
    const [surveys, setSurveys] = useState([]);
    const [loading, setLoading] = useState(true);

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const r = await api.get('/my/nps/surveys');
            setSurveys(r?.surveys || []);
        } catch (e) { notify.error('Erreur'); }
        finally { setLoading(false); }
    }, [notify]);

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

    const stats = useMemo(() => npsAggregate(surveys), [surveys]);
    const timeline = useMemo(() => buildNpsTimeline(surveys), [surveys]);

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">{t('nav.nps', lang)}</h1>
                    <p className="page-subtitle">Satisfaction client agrégée - toutes lignes confondues.</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={load}><Icons.Refresh className="w-4 h-4" /> Actualiser</button>
                </div>
            </div>
            <div className="page-content">
                {loading ? <p>{t('common.loading', lang)}</p> : (
                    <>
                        <div className="stats-grid" style={{ marginBottom: '1rem' }}>
                            <div className="stat-card"><div className="stat-icon blue"><Icons.Star className="w-6 h-6" /></div><div><div className="stat-label">Score moyen</div><div className="stat-value">{stats.avg.toFixed(2)}</div></div></div>
                            <div className="stat-card"><div className="stat-icon gray"><Icons.Users className="w-6 h-6" /></div><div><div className="stat-label">Réponses</div><div className="stat-value">{stats.total}</div></div></div>
                            <div className="stat-card"><div className="stat-icon green"><Icons.Check className="w-6 h-6" /></div><div><div className="stat-label">Promoteurs</div><div className="stat-value">{stats.promotersPct}%</div></div></div>
                            <div className="stat-card"><div className="stat-icon orange"><Icons.AlertCircle className="w-6 h-6" /></div><div><div className="stat-label">Détracteurs</div><div className="stat-value">{stats.detractorsPct}%</div></div></div>
                            <div className="stat-card"><div className="stat-icon purple"><Icons.Sparkles className="w-6 h-6" /></div><div><div className="stat-label">NPS</div><div className="stat-value">{stats.nps}</div></div></div>
                        </div>
                        <div className="card" style={{ padding: '1rem 1.25rem', marginBottom: '1rem' }}>
                            <h3 style={{ margin: '0 0 0.75rem', fontSize: '0.95rem' }}>Évolution des scores</h3>
                            <NpsSparkline data={timeline} />
                        </div>
                        <div className="card" style={{ padding: '1rem 1.25rem' }}>
                            <h3 style={{ margin: '0 0 0.75rem', fontSize: '0.95rem' }}>Derniers retours</h3>
                            <NpsSurveysTable surveys={surveys} />
                        </div>
                    </>
                )}
            </div>
        </>
    );
};

function buildNpsTimeline(surveys) {
    const points = (surveys || [])
        .filter(s => s.score != null && s.created_at)
        .map(s => ({ t: new Date(s.created_at).getTime(), v: Number(s.score) }))
        .sort((a, b) => a.t - b.t);
    return points;
}

const NpsSparkline = ({ data }) => {
    if (!data || data.length < 2) {
        return <p style={{ color: 'var(--text-muted)', fontSize: '0.85rem', margin: 0 }}>Pas assez de données pour afficher une tendance.</p>;
    }
    const w = 720, h = 140, pad = 24;
    const minT = data[0].t, maxT = data[data.length - 1].t;
    const minV = 1, maxV = 5;
    const x = (t) => pad + ((t - minT) / Math.max(1, (maxT - minT))) * (w - 2 * pad);
    const y = (v) => h - pad - ((v - minV) / (maxV - minV)) * (h - 2 * pad);
    const path = data.map((p, i) => `${i === 0 ? 'M' : 'L'}${x(p.t).toFixed(1)},${y(p.v).toFixed(1)}`).join(' ');
    return (
        <svg viewBox={`0 0 ${w} ${h}`} width="100%" height="140" preserveAspectRatio="none" style={{ display: 'block' }}>
            <line x1={pad} y1={y(3)} x2={w - pad} y2={y(3)} stroke="#e2e8f0" strokeDasharray="3 3" />
            <path d={path} fill="none" stroke="var(--primary)" strokeWidth="2" />
            {data.map((p, i) => (
                <circle key={i} cx={x(p.t)} cy={y(p.v)} r="2.5" fill="var(--primary)" />
            ))}
            <text x={pad} y={h - 4} fontSize="10" fill="#64748b">{new Date(minT).toLocaleDateString('fr-CH')}</text>
            <text x={w - pad} y={h - 4} fontSize="10" fill="#64748b" textAnchor="end">{new Date(maxT).toLocaleDateString('fr-CH')}</text>
        </svg>
    );
};

// ==================== VOICE CLONES VIEW ====================
const VoiceClonesView = () => {
    const { notify } = useApp();
    const lang = useLang();
    const [items, setItems] = useState([]);
    const [loading, setLoading] = useState(true);
    const [show, setShow] = useState(false);
    const [draft, setDraft] = useState({ label: '', provider: 'elevenlabs', sample_url: '', language: 'fr', api_key: '' });
    const [saving, setSaving] = useState(false);

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const r = await api.get('/my/voice-clones');
            setItems(r?.voice_clones || r?.clones || []);
        } catch (e) { notify.error('Erreur'); }
        finally { setLoading(false); }
    }, [notify]);

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

    const create = async () => {
        if (!draft.label.trim() || !draft.sample_url.trim()) return notify.error('Libellé et sample_url requis');
        setSaving(true);
        try {
            const r = await api.post('/my/voice-clones', draft);
            if (r?.error) return notify.error(r.error);
            notify.success('Voix créée');
            setShow(false);
            setDraft({ label: '', provider: 'elevenlabs', sample_url: '', language: 'fr', api_key: '' });
            load();
        } catch (e) { notify.error('Erreur: ' + e.message); }
        finally { setSaving(false); }
    };

    const remove = async (v) => {
        if (!confirm(`Supprimer la voix "${v.label}" ?`)) return;
        try {
            const r = await api.del(`/my/voice-clones/${v.id}`);
            if (r?.error) notify.error(r.error);
            else { notify.success('Supprimée'); load(); }
        } catch (e) { notify.error('Erreur'); }
    };

    const statusBadge = (s) => {
        const map = { ready: ['#dcfce7', '#15803d'], training: ['#fef3c7', '#854d0e'], failed: ['#fee2e2', '#b91c1c'], pending: ['#e0e7ff', '#4338ca'] };
        const [bg, fg] = map[s] || ['#f1f5f9', '#475569'];
        return <span style={{ background: bg, color: fg, padding: '0.2rem 0.6rem', borderRadius: 999, fontSize: '0.75rem', fontWeight: 600 }}>{s || '-'}</span>;
    };

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">{t('nav.voice_clones', lang)}</h1>
                    <p className="page-subtitle">Créez vos propres voix synthétiques pour vos bots vocaux (OpenAI, ElevenLabs).</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={load}><Icons.Refresh className="w-4 h-4" /> Actualiser</button>
                    <button className="btn btn-primary btn-sm" onClick={() => setShow(true)}><Icons.Plus className="w-4 h-4" /> Ajouter une voix</button>
                </div>
            </div>
            <div className="page-content">
                {show && (
                    <div className="card" style={{ padding: '1rem', marginBottom: '1rem', border: '2px solid var(--primary-light)' }}>
                        <h3 style={{ margin: '0 0 0.75rem' }}>Nouvelle voix</h3>
                        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '0.75rem' }}>
                            <div className="form-row"><label>Libellé *</label><input className="form-input" value={draft.label} onChange={e => setDraft({ ...draft, label: e.target.value })} placeholder="Ex: Voix Marie" /></div>
                            <div className="form-row"><label>Fournisseur</label>
                                <select className="form-input" value={draft.provider} onChange={e => setDraft({ ...draft, provider: e.target.value })}>
                                    <option value="elevenlabs">ElevenLabs</option>
                                    <option value="openai">OpenAI</option>
                                </select>
                            </div>
                            <div className="form-row" style={{ gridColumn: '1 / -1' }}><label>URL d'un échantillon audio (mp3/wav)</label><input className="form-input" value={draft.sample_url} onChange={e => setDraft({ ...draft, sample_url: e.target.value })} placeholder="https://r2.vocal.ch/..." /></div>
                            <div className="form-row"><label>Langue</label>
                                <select className="form-input" value={draft.language} onChange={e => setDraft({ ...draft, language: e.target.value })}>
                                    <option value="fr">Français</option>
                                    <option value="de">Deutsch</option>
                                    <option value="en">English</option>
                                    <option value="it">Italiano</option>
                                </select>
                            </div>
                            <div className="form-row"><label>Clé API (si requis)</label><input className="form-input" value={draft.api_key} onChange={e => setDraft({ ...draft, api_key: e.target.value })} placeholder="optionnel" /></div>
                        </div>
                        <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end', marginTop: '0.75rem' }}>
                            <button className="btn btn-secondary" onClick={() => setShow(false)}>{t('common.cancel', lang)}</button>
                            <button className="btn btn-primary" onClick={create} disabled={saving}>{saving ? '…' : t('common.save', lang)}</button>
                        </div>
                    </div>
                )}
                {loading ? <p>{t('common.loading', lang)}</p> : items.length === 0 ? (
                    <div className="card" style={{ padding: '3rem 2rem', textAlign: 'center', color: 'var(--text-muted)' }}>
                        <Icons.Sparkles className="w-10 h-10" style={{ margin: '0 auto 0.75rem', opacity: 0.4 }} />
                        <p style={{ margin: 0 }}>{t('common.empty', lang)}</p>
                    </div>
                ) : (
                    <div className="card">
                        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.875rem' }}>
                            <thead><tr style={{ background: '#f8fafc', textAlign: 'left' }}>
                                <th style={{ padding: '0.65rem 1rem' }}>Libellé</th>
                                <th>Fournisseur</th>
                                <th>Langue</th>
                                <th>Statut</th>
                                <th>Créé le</th>
                                <th></th>
                            </tr></thead>
                            <tbody>{items.map(v => (
                                <tr key={v.id} style={{ borderTop: '1px solid var(--border)' }}>
                                    <td style={{ padding: '0.6rem 1rem', fontWeight: 600 }}>{v.label}</td>
                                    <td>{v.provider}</td>
                                    <td>{v.language || '-'}</td>
                                    <td>{statusBadge(v.status)}</td>
                                    <td style={{ color: 'var(--text-muted)' }}>{v.created_at ? new Date(v.created_at).toLocaleDateString('fr-CH') : '-'}</td>
                                    <td><button className="btn btn-secondary btn-sm" onClick={() => remove(v)} style={{ color: '#dc2626' }}><Icons.Trash className="w-4 h-4" /></button></td>
                                </tr>
                            ))}</tbody>
                        </table>
                    </div>
                )}
            </div>
        </>
    );
};

// ==================== STUDIO VOIX (TTS on-demand → MP3) ====================
const StudioView = () => {
    const { notify } = useApp();
    const lang = useLang();
    const [text, setText] = useState('');
    const [label, setLabel] = useState('');
    const [provider, setProvider] = useState('openai');
    const [model, setModel] = useState('tts-1');
    const [voice, setVoice] = useState('alloy');
    const [voiceCloneId, setVoiceCloneId] = useState('');
    const [language, setLanguage] = useState('fr');
    const [format, setFormat] = useState('mp3');
    const [speed, setSpeed] = useState(1.0);
    const [voicesData, setVoicesData] = useState({ openai: { voices: [], models: [] }, elevenlabs: { available: false }, custom: [] });
    const [items, setItems] = useState([]);
    const [loading, setLoading] = useState(true);
    const [generating, setGenerating] = useState(false);
    const [lastGenerated, setLastGenerated] = useState(null);

    const loadVoices = useCallback(async () => {
        try {
            const r = await api.get('/my/tts/voices');
            if (r) setVoicesData(r);
        } catch (e) {}
    }, []);

    const loadList = useCallback(async () => {
        setLoading(true);
        try {
            const r = await api.get('/my/tts');
            setItems(r?.recordings || []);
        } catch (e) { notify.error('Erreur chargement'); }
        finally { setLoading(false); }
    }, [notify]);

    useEffect(() => { loadVoices(); loadList(); }, [loadVoices, loadList]);

    const generate = async () => {
        const txt = text.trim();
        if (!txt) return notify.error('Texte requis');
        if (txt.length > 4000) return notify.error('Texte trop long (max 4000 caractères)');
        setGenerating(true);
        try {
            const payload = {
                text: txt,
                label: label.trim() || txt.slice(0, 60),
                provider,
                model,
                language,
                format,
                speed: parseFloat(speed) || 1.0,
            };
            if (voiceCloneId) payload.voice_clone_id = parseInt(voiceCloneId);
            else payload.voice = voice;
            const r = await api.post('/my/tts', payload);
            if (r?.error) return notify.error(r.error + (r.detail ? ` - ${r.detail}` : ''));
            notify.success('Audio généré');
            setLastGenerated(r);
            loadList();
        } catch (e) {
            notify.error('Erreur: ' + e.message);
        } finally { setGenerating(false); }
    };

    const remove = async (rec) => {
        if (!confirm(`Supprimer "${rec.label}" ?`)) return;
        try {
            const r = await api.del(`/my/tts/${rec.id}`);
            if (r?.error) notify.error(r.error);
            else { notify.success('Supprimé'); loadList(); if (lastGenerated?.id === rec.id) setLastGenerated(null); }
        } catch (e) { notify.error('Erreur'); }
    };

    const copyUrl = (url) => {
        navigator.clipboard?.writeText(url).then(() => notify.success('URL copiée'));
    };

    const useExamples = [
        { l: 'Message d\'accueil', t: "Bonjour et bienvenue chez Vocal. Pour rejoindre les ventes, dites 'ventes'. Pour le support, dites 'support'." },
        { l: 'Message de vacances', t: "Notre bureau est fermé du 23 décembre au 5 janvier. Laissez un message après le bip et nous vous rappellerons dès notre retour." },
        { l: 'Renvoi sur mobile', t: "Merci de patienter, nous vous transférons vers un conseiller." },
        { l: 'Hors horaires', t: "Bonjour, nos bureaux sont actuellement fermés. Nos horaires sont du lundi au vendredi, de 8h à 18h." },
    ];

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">{t('nav.studio', lang)}</h1>
                    <p className="page-subtitle">Générez un MP3 à partir d'un texte. Réutilisable partout : accueil, vacances, IVR, voicemail, hold.</p>
                </div>
                <div className="page-actions">
                    <button className="btn btn-secondary btn-sm" onClick={loadList}><Icons.Refresh className="w-4 h-4" /> Actualiser</button>
                </div>
            </div>
            <div className="page-content">
                <div className="card" style={{ padding: '1.25rem', marginBottom: '1rem' }}>
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem' }}>
                        <div className="form-row" style={{ gridColumn: '1 / -1' }}>
                            <label>Texte à dire ({text.length}/4000)</label>
                            <textarea
                                className="form-input"
                                value={text}
                                onChange={e => setText(e.target.value)}
                                rows={5}
                                maxLength={4000}
                                placeholder="Bonjour, vous êtes bien chez…"
                                style={{ fontFamily: 'inherit', resize: 'vertical' }}
                            />
                            <div style={{ display: 'flex', gap: '0.4rem', flexWrap: 'wrap', marginTop: '0.4rem' }}>
                                {useExamples.map((ex, i) => (
                                    <button key={i} type="button" className="btn btn-secondary btn-sm"
                                        onClick={() => { setText(ex.t); if (!label) setLabel(ex.l); }}
                                        style={{ fontSize: '0.75rem' }}>{ex.l}</button>
                                ))}
                            </div>
                        </div>

                        <div className="form-row">
                            <label>Libellé (optionnel)</label>
                            <input className="form-input" value={label} onChange={e => setLabel(e.target.value)} placeholder="Ex: Accueil semaine" />
                        </div>
                        <div className="form-row">
                            <label>Langue</label>
                            <select className="form-input" value={language} onChange={e => setLanguage(e.target.value)}>
                                <option value="fr">Français</option>
                                <option value="de">Deutsch</option>
                                <option value="en">English</option>
                                <option value="it">Italiano</option>
                            </select>
                        </div>

                        <div className="form-row">
                            <label>Voix custom (clone)</label>
                            <select className="form-input" value={voiceCloneId}
                                onChange={e => {
                                    setVoiceCloneId(e.target.value);
                                    if (e.target.value) {
                                        const c = voicesData.custom.find(v => String(v.id) === e.target.value);
                                        if (c) setProvider(c.provider);
                                    }
                                }}>
                                <option value="">- Aucune (voix standard) -</option>
                                {voicesData.custom.map(v => (
                                    <option key={v.id} value={v.id}>{v.label} ({v.provider})</option>
                                ))}
                            </select>
                        </div>
                        <div className="form-row">
                            <label>Fournisseur</label>
                            <select className="form-input" value={provider} disabled={!!voiceCloneId}
                                onChange={e => {
                                    setProvider(e.target.value);
                                    if (e.target.value === 'elevenlabs') setModel('eleven_multilingual_v2');
                                    else { setModel('tts-1'); setVoice('alloy'); }
                                }}>
                                <option value="openai">OpenAI (intégré)</option>
                                <option value="elevenlabs" disabled={!voicesData.elevenlabs?.available}>
                                    ElevenLabs {voicesData.elevenlabs?.available ? '' : '(non configuré)'}
                                </option>
                            </select>
                        </div>

                        {!voiceCloneId && provider === 'openai' && (
                            <>
                                <div className="form-row">
                                    <label>Voix</label>
                                    <select className="form-input" value={voice} onChange={e => setVoice(e.target.value)}>
                                        {(voicesData.openai?.voices || []).map(v => <option key={v} value={v}>{v}</option>)}
                                    </select>
                                </div>
                                <div className="form-row">
                                    <label>Modèle</label>
                                    <select className="form-input" value={model} onChange={e => setModel(e.target.value)}>
                                        {(voicesData.openai?.models || []).map(m => <option key={m} value={m}>{m}</option>)}
                                    </select>
                                </div>
                            </>
                        )}
                        {!voiceCloneId && provider === 'elevenlabs' && (
                            <div className="form-row" style={{ gridColumn: '1 / -1' }}>
                                <label>Voice ID ElevenLabs</label>
                                <input className="form-input" value={voice} onChange={e => setVoice(e.target.value)} placeholder="Ex: 21m00Tcm4TlvDq8ikWAM (Rachel)" />
                                <small style={{ color: 'var(--text-muted)' }}>Trouvable sur https://elevenlabs.io/app/voice-library</small>
                            </div>
                        )}

                        <div className="form-row">
                            <label>Format</label>
                            <select className="form-input" value={format} onChange={e => setFormat(e.target.value)}>
                                <option value="mp3">MP3</option>
                                <option value="wav">WAV</option>
                                <option value="ogg">OGG</option>
                            </select>
                        </div>
                        <div className="form-row">
                            <label>Vitesse: {speed}x</label>
                            <input type="range" min="0.5" max="2" step="0.05" value={speed} onChange={e => setSpeed(e.target.value)} />
                        </div>
                    </div>

                    <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end', marginTop: '1rem', borderTop: '1px solid var(--border)', paddingTop: '1rem' }}>
                        <button className="btn btn-primary" onClick={generate} disabled={generating || !text.trim()}>
                            {generating ? 'Génération…' : '🎙️ Générer le MP3'}
                        </button>
                    </div>

                    {lastGenerated && lastGenerated.file_url && (
                        <div style={{ marginTop: '1rem', padding: '1rem', background: '#f0fdf4', border: '1px solid #86efac', borderRadius: '0.5rem' }}>
                            <div style={{ fontWeight: 600, marginBottom: '0.5rem', color: '#15803d' }}>✓ {lastGenerated.label}</div>
                            <audio controls src={lastGenerated.file_url} style={{ width: '100%', marginBottom: '0.5rem' }} />
                            <div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap', alignItems: 'center', fontSize: '0.85rem' }}>
                                <code style={{ background: '#fff', padding: '0.3rem 0.5rem', borderRadius: 4, flex: 1, wordBreak: 'break-all' }}>{lastGenerated.file_url}</code>
                                <button className="btn btn-secondary btn-sm" onClick={() => copyUrl(lastGenerated.file_url)}>📋 Copier l'URL</button>
                                <a className="btn btn-secondary btn-sm" href={lastGenerated.file_url} download={`${lastGenerated.label}.${lastGenerated.format}`}>⬇ Télécharger</a>
                            </div>
                            <div style={{ marginTop: '0.5rem', fontSize: '0.75rem', color: 'var(--text-muted)' }}>
                                {lastGenerated.char_count} caractères · ≈ {(lastGenerated.cost_chf || 0).toFixed(3)} CHF · {(lastGenerated.file_size / 1024).toFixed(1)} KB
                            </div>
                        </div>
                    )}
                </div>

                <div className="card" style={{ padding: '1rem' }}>
                    <h3 style={{ margin: '0 0 0.75rem' }}>Mes enregistrements</h3>
                    {loading ? <p>{t('common.loading', lang)}</p> : items.length === 0 ? (
                        <div style={{ padding: '2rem', textAlign: 'center', color: 'var(--text-muted)' }}>
                            <p>{t('common.empty', lang)}</p>
                        </div>
                    ) : (
                        <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                            {items.map(rec => (
                                <div key={rec.id} style={{ border: '1px solid var(--border)', borderRadius: '0.5rem', padding: '0.75rem', background: '#fff' }}>
                                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.4rem', flexWrap: 'wrap', gap: '0.5rem' }}>
                                        <div>
                                            <div style={{ fontWeight: 600 }}>{rec.label}</div>
                                            <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>
                                                {rec.provider} · {rec.voice || '-'} · {rec.language} · {rec.char_count} car. · {new Date(rec.created_at).toLocaleString('fr-CH')}
                                            </div>
                                        </div>
                                        <div style={{ display: 'flex', gap: '0.4rem' }}>
                                            <button className="btn btn-secondary btn-sm" onClick={() => copyUrl(rec.file_url)} title="Copier l'URL">📋</button>
                                            <a className="btn btn-secondary btn-sm" href={rec.file_url} download={`${rec.label}.${rec.format}`} title="Télécharger">⬇</a>
                                            <button className="btn btn-secondary btn-sm" style={{ color: '#dc2626' }} onClick={() => remove(rec)} title="Supprimer"><Icons.Trash className="w-4 h-4" /></button>
                                        </div>
                                    </div>
                                    <audio controls src={rec.file_url} style={{ width: '100%', height: 32 }} />
                                    <details style={{ marginTop: '0.4rem', fontSize: '0.8rem', color: 'var(--text-muted)' }}>
                                        <summary style={{ cursor: 'pointer' }}>Texte</summary>
                                        <p style={{ marginTop: '0.4rem', whiteSpace: 'pre-wrap' }}>{rec.text}</p>
                                    </details>
                                </div>
                            ))}
                        </div>
                    )}
                </div>
            </div>
        </>
    );
};

// ==================== MODULE GATE (affiche une CTA si module non activé) ====================
const ModulesContext = React.createContext({ modules: [], reload: () => {}, loading: false });

const ModulesProvider = ({ children }) => {
    const { user } = useApp();
    const [modules, setModules] = useState([]);
    const [loading, setLoading] = useState(false);
    const reload = useCallback(async () => {
        if (!user) { setModules([]); return; }
        setLoading(true);
        try {
            const r = await api.get('/my/modules');
            setModules(r?.modules || []);
        } catch {} finally { setLoading(false); }
    }, [user]);
    useEffect(() => { reload(); }, [reload]);
    const val = useMemo(() => ({ modules, reload, loading }), [modules, reload, loading]);
    return <ModulesContext.Provider value={val}>{children}</ModulesContext.Provider>;
};
const useModules = () => React.useContext(ModulesContext);
const useModuleEnabled = (code) => {
    const { modules } = useModules();
    return modules.find(m => m.code === code)?.enabled || false;
};

const ModuleGate = ({ code, children }) => {
    const { modules, loading, reload } = useModules();
    const { navigate, notify } = useApp();
    const [activating, setActivating] = useState(false);
    if (loading) return <div className="page-content"><p>Chargement…</p></div>;
    const m = modules.find(x => x.code === code);
    if (m?.enabled) return children;
    const activate = async () => {
        if (!m) return;
        if (m.price_chf > 0) {
            if (!confirm(`Activer "${m.name}" pour ${m.price_chf.toFixed(2)} CHF/${m.billing_period === 'year' ? 'an' : 'mois'} ?\n\nDébité aujourd'hui : ${((m.price_chf || 0) + (m.setup_fee_chf || 0)).toFixed(2)} CHF depuis votre wallet.`)) return;
        }
        setActivating(true);
        try {
            const r = await api.post(`/my/modules/${code}/activate`);
            if (r?.error) {
                if (r.required) notify.error(`Solde insuffisant. Requis: ${r.required.toFixed(2)} CHF`);
                else notify.error(r.error);
            } else {
                notify.success('Module activé');
                reload();
            }
        } finally { setActivating(false); }
    };
    return (
        <div className="page-content" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '60vh' }}>
            <div className="card" style={{ padding: '2rem 2.5rem', maxWidth: 520, textAlign: 'center', border: '2px dashed var(--border)' }}>
                <Icons.Sparkles className="w-12 h-12" style={{ margin: '0 auto 1rem', color: '#6366f1' }} />
                <h2 style={{ margin: '0 0 0.5rem' }}>{m ? m.name : 'Module requis'}</h2>
                <p style={{ color: 'var(--text-muted)', marginBottom: '1.25rem' }}>
                    {m ? m.description : 'Cette fonctionnalité nécessite l\'activation d\'un module.'}
                </p>
                {m && (
                    <div style={{ background: '#f8fafc', padding: '0.9rem', borderRadius: 8, marginBottom: '1rem' }}>
                        {m.price_chf > 0 ? (
                            <>
                                <div style={{ fontSize: '1.5rem', fontWeight: 700 }}>
                                    {m.price_chf.toFixed(2)} CHF<span style={{ fontSize: '0.85rem', color: 'var(--text-muted)' }}> /{m.billing_period === 'year' ? 'an' : 'mois'}</span>
                                </div>
                                {m.trial_days > 0 && <div style={{ color: '#16a34a', fontWeight: 600 }}>🎁 {m.trial_days} jours gratuits</div>}
                            </>
                        ) : (
                            <div style={{ fontSize: '1.5rem', fontWeight: 700, color: '#16a34a' }}>GRATUIT</div>
                        )}
                    </div>
                )}
                <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'center' }}>
                    <button className="btn btn-secondary" onClick={() => navigate('modules')}>Voir tous les modules</button>
                    {m && <button className="btn btn-primary" onClick={activate} disabled={activating}>
                        {activating ? '…' : (m.price_chf > 0 ? `Activer pour ${m.price_chf.toFixed(2)} CHF/mois` : 'Activer (gratuit)')}
                    </button>}
                </div>
            </div>
        </div>
    );
};

// ==================== MODULES (catalogue d'options activables) ====================
const ModulesView = () => {
    const { notify, navigate } = useApp();
    const lang = useLang();
    const [items, setItems] = useState([]);
    const [loading, setLoading] = useState(true);
    const [pendingActivate, setPendingActivate] = useState(null);
    const [working, setWorking] = useState(false);

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const r = await api.get('/my/modules');
            setItems(r?.modules || []);
        } catch (e) { notify.error('Erreur chargement modules'); }
        finally { setLoading(false); }
    }, [notify]);

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

    const activate = async (m) => {
        setWorking(true);
        try {
            const r = await api.post(`/my/modules/${m.code}/activate`);
            if (r?.error) {
                if (r.required) {
                    notify.error(`Solde insuffisant. Requis: ${r.required.toFixed(2)} CHF, vous avez ${r.balance.toFixed(2)} CHF.`);
                } else {
                    notify.error(r.error);
                }
            } else {
                if (r.charged_chf > 0) notify.success(`✓ Activé. Débité: ${r.charged_chf.toFixed(2)} CHF`);
                else notify.success('✓ Module activé');
                load();
            }
        } catch (e) { notify.error('Erreur: ' + e.message); }
        finally { setWorking(false); setPendingActivate(null); }
    };

    const deactivate = async (m) => {
        if (!confirm(`Désactiver "${m.name}" ? Vous ne serez plus facturé au prochain renouvellement.`)) return;
        setWorking(true);
        try {
            const r = await api.post(`/my/modules/${m.code}/deactivate`);
            if (r?.error) notify.error(r.error);
            else { notify.success('Module désactivé'); load(); }
        } catch (e) { notify.error('Erreur'); }
        finally { setWorking(false); }
    };

    const grouped = useMemo(() => {
        const map = {};
        for (const m of items) {
            const cat = m.category || 'general';
            if (!map[cat]) map[cat] = [];
            map[cat].push(m);
        }
        return map;
    }, [items]);

    const categoryLabels = {
        ai: '🤖 Intelligence artificielle',
        communication: '💬 Communication',
        crm: '👥 CRM & Contacts',
        monitoring: '📊 Monitoring & Live',
        general: '⚙️ Général',
    };

    const totalMonthly = items.filter(m => m.enabled && !m.in_trial).reduce((s, m) => s + (m.price_paid_chf || m.price_chf || 0), 0);

    return (
        <>
            <div className="page-header">
                <div>
                    <h1 className="page-title">{t('nav.modules', lang)}</h1>
                    <p className="page-subtitle">Activez les fonctionnalités dont vous avez besoin. Désactivables à tout moment.</p>
                </div>
                <div className="page-actions">
                    <div style={{ background: '#eef2ff', color: '#4338ca', padding: '0.5rem 0.9rem', borderRadius: 8, fontWeight: 600 }}>
                        Total mensuel: {totalMonthly.toFixed(2)} CHF
                    </div>
                </div>
            </div>
            <div className="page-content">
                {loading ? <p>{t('common.loading', lang)}</p> : items.length === 0 ? (
                    <div className="card" style={{ padding: '3rem 2rem', textAlign: 'center', color: 'var(--text-muted)' }}>
                        <p>Aucun module disponible.</p>
                    </div>
                ) : Object.entries(grouped).map(([cat, mods]) => (
                    <div key={cat} style={{ marginBottom: '1.5rem' }}>
                        <h2 style={{ fontSize: '1.05rem', margin: '0 0 0.6rem', color: 'var(--text-muted)', fontWeight: 600 }}>
                            {categoryLabels[cat] || cat}
                        </h2>
                        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))', gap: '0.75rem' }}>
                            {mods.map(m => (
                                <div key={m.code} className="card" style={{
                                    padding: '1rem',
                                    border: m.enabled ? '2px solid #16a34a' : '1px solid var(--border)',
                                    background: m.enabled ? '#f0fdf4' : '#fff',
                                    position: 'relative',
                                }}>
                                    {m.enabled && (
                                        <div style={{ position: 'absolute', top: 8, right: 8, background: '#16a34a', color: '#fff',
                                            padding: '0.15rem 0.5rem', borderRadius: 999, fontSize: '0.7rem', fontWeight: 700 }}>
                                            {m.in_trial ? `ESSAI (${m.trial_until ? new Date(m.trial_until).toLocaleDateString('fr-CH') : ''})` : 'ACTIF'}
                                        </div>
                                    )}
                                    <div style={{ fontWeight: 700, fontSize: '1.05rem', marginBottom: '0.25rem' }}>{m.name}</div>
                                    <div style={{ fontSize: '0.85rem', color: 'var(--text-muted)', minHeight: 38, marginBottom: '0.6rem' }}>
                                        {m.description}
                                    </div>
                                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: '0.5rem' }}>
                                        <div>
                                            {m.price_chf > 0 ? (
                                                <div>
                                                    <span style={{ fontSize: '1.4rem', fontWeight: 700, color: '#0f172a' }}>{m.price_chf.toFixed(2)} CHF</span>
                                                    <span style={{ color: 'var(--text-muted)', marginLeft: 4 }}>/{m.billing_period === 'year' ? 'an' : 'mois'}</span>
                                                    {m.setup_fee_chf > 0 && <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>+ {m.setup_fee_chf.toFixed(2)} CHF activation</div>}
                                                    {m.trial_days > 0 && !m.enabled && <div style={{ fontSize: '0.75rem', color: '#16a34a', fontWeight: 600 }}>🎁 {m.trial_days} jours gratuits</div>}
                                                </div>
                                            ) : (
                                                <span style={{ fontWeight: 700, color: '#16a34a' }}>GRATUIT</span>
                                            )}
                                        </div>
                                        <div>
                                            {m.enabled ? (
                                                <button className="btn btn-secondary btn-sm" disabled={working} onClick={() => deactivate(m)}>
                                                    Désactiver
                                                </button>
                                            ) : (
                                                <button className="btn btn-primary btn-sm" disabled={working}
                                                    onClick={() => m.price_chf > 0 ? setPendingActivate(m) : activate(m)}>
                                                    {m.price_chf > 0 ? 'Activer' : 'Activer (gratuit)'}
                                                </button>
                                            )}
                                        </div>
                                    </div>
                                    {m.enabled && m.expires_at && (
                                        <div style={{ marginTop: '0.5rem', fontSize: '0.75rem', color: 'var(--text-muted)' }}>
                                            Renouvellement le {new Date(m.expires_at).toLocaleDateString('fr-CH')}
                                            {m.total_paid_chf > 0 && ` · Total payé: ${m.total_paid_chf.toFixed(2)} CHF`}
                                        </div>
                                    )}
                                </div>
                            ))}
                        </div>
                    </div>
                ))}
            </div>

            {pendingActivate && (
                <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1000 }}
                     onClick={() => setPendingActivate(null)}>
                    <div className="card" style={{ padding: '1.5rem', maxWidth: 460, width: '90%', background: '#fff' }} onClick={e => e.stopPropagation()}>
                        <h3 style={{ margin: '0 0 0.75rem' }}>Activer "{pendingActivate.name}" ?</h3>
                        <p style={{ marginBottom: '1rem', color: 'var(--text-muted)' }}>{pendingActivate.description}</p>
                        <div style={{ background: '#f8fafc', padding: '0.75rem', borderRadius: 6, marginBottom: '1rem' }}>
                            <div>Prix mensuel : <strong>{pendingActivate.price_chf.toFixed(2)} CHF</strong></div>
                            {pendingActivate.setup_fee_chf > 0 && <div>Frais d'activation : <strong>{pendingActivate.setup_fee_chf.toFixed(2)} CHF</strong></div>}
                            {pendingActivate.trial_days > 0 ? (
                                <div style={{ color: '#16a34a', fontWeight: 600, marginTop: '0.4rem' }}>
                                    🎁 Essai gratuit de {pendingActivate.trial_days} jours - débit aujourd'hui : {(pendingActivate.setup_fee_chf || 0).toFixed(2)} CHF
                                </div>
                            ) : (
                                <div style={{ marginTop: '0.4rem' }}>
                                    Débit aujourd'hui : <strong>{((pendingActivate.price_chf || 0) + (pendingActivate.setup_fee_chf || 0)).toFixed(2)} CHF</strong> (depuis votre wallet)
                                </div>
                            )}
                        </div>
                        <p style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>
                            Renouvellement automatique chaque mois. Désactivable à tout moment depuis cette page.
                        </p>
                        <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end', marginTop: '1rem' }}>
                            <button className="btn btn-secondary" onClick={() => setPendingActivate(null)}>Annuler</button>
                            <button className="btn btn-primary" disabled={working} onClick={() => activate(pendingActivate)}>
                                {working ? '…' : 'Confirmer l\'activation'}
                            </button>
                        </div>
                    </div>
                </div>
            )}
        </>
    );
};

// ==================== IMPERSONATION BANNER ====================
const ImpersonationBanner = () => {
    const { user, logout } = useApp();
    const isImpersonating = (() => {
        try { return sessionStorage.getItem('vocal_my_impersonating') === '1'; }
        catch (e) { return false; }
    })();
    if (!isImpersonating) return null;
    const exit = () => {
        try { sessionStorage.removeItem('vocal_my_impersonating'); } catch (e) {}
        logout();
    };
    return (
        <div style={{
            background: 'linear-gradient(135deg, #f59e0b, #ef4444)',
            color: '#fff', padding: '0.5rem 1rem', display: 'flex',
            alignItems: 'center', justifyContent: 'space-between', gap: '1rem',
            fontSize: '0.8125rem', fontWeight: 600, letterSpacing: '0.01em',
            boxShadow: '0 2px 6px rgba(0,0,0,0.08)', zIndex: 100,
        }}>
            <span>👁️ Mode admin - connecté en tant que <strong>{user?.email || user?.client?.email}</strong></span>
            <button onClick={exit} style={{
                background: 'rgba(255,255,255,0.2)', color: '#fff', border: '1px solid rgba(255,255,255,0.4)',
                borderRadius: '999px', padding: '0.25rem 0.875rem', fontWeight: 600, cursor: 'pointer',
                fontSize: '0.75rem',
            }}>Quitter l'impersonation</button>
        </div>
    );
};

// ==================== APP ROOT ====================
const App = () => {
    const { user, view, refreshProfile } = useApp();
    useEffect(() => { if (user) refreshProfile(); }, []);

    if (!user) return <LoginScreen />;
    return (
        <div className="app-layout">
            <Sidebar />
            <div className="main-content">
                <ImpersonationBanner />
                <MobileHeader />
                {view === 'dashboard' && <DashboardView />}
                {view === 'lines' && <LinesView />}
                {view === 'line-detail' && <LineDetailView />}
                {view === 'calls' && <CallsView />}
                {view === 'sms' && <MessagesView kind="sms" />}
                {view === 'whatsapp' && <MessagesView kind="whatsapp" />}
                {view === 'bots' && <BotsView />}
                {view === 'contacts' && <ContactsView />}
                {view === 'conversations' && <ModuleGate code="whatsapp"><ConversationsView /></ModuleGate>}
                {view === 'nps' && <ModuleGate code="nps"><NpsView /></ModuleGate>}
                {view === 'voice-clones' && <ModuleGate code="voice_clones"><VoiceClonesView /></ModuleGate>}
                {view === 'studio' && <ModuleGate code="tts_studio"><StudioView /></ModuleGate>}
                {view === 'modules' && <ModulesView />}
                {view === 'proxy' && <ProxyNumbersView />}
                {view === 'spam' && <SpamView />}
                {view === 'billing' && <BillingView />}
                {view === 'subscriptions' && <SubscriptionsView />}
                {view === 'porting' && <PortingView />}
                {view === 'api-keys' && <ApiKeysView />}
                {view === 'settings' && <SettingsView />}
            </div>
        </div>
    );
};

ReactDOM.createRoot(document.getElementById('app')).render(
    <AppProvider><ModulesProvider><PhoneHistoryProvider><App /></PhoneHistoryProvider></ModulesProvider></AppProvider>
);
