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

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

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}`;
}

// ==================== 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>),
};

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','billing','subscriptions','api-keys','settings'].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 navigate = useCallback((v, opts = {}) => {
        setView(v);
        setSidebarOpen(false);
        if (opts.lineId) setSelectedLineId(opts.lineId);
        if (v !== 'line-detail') {
            try { window.history.replaceState(null, '', `#${v}`); } catch (e) {}
        }
    }, []);

    const value = useMemo(() => ({
        user, view, sidebarOpen, setSidebarOpen, selectedLineId, setSelectedLineId,
        login, logout, navigate, notify, refreshProfile, setUser,
    }), [user, view, sidebarOpen, selectedLineId, 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 items = [
        { id: 'dashboard', label: 'Tableau de bord', icon: Icons.Home, section: 'main' },
        { id: 'lines', label: 'Mes lignes', icon: Icons.Phone, section: 'main' },
        { id: 'calls', label: 'Appels', icon: Icons.PhoneIn, section: 'main' },
        { id: 'sms', label: 'SMS', icon: Icons.Send, section: 'main' },
        { id: 'whatsapp', label: 'WhatsApp', icon: Icons.Chat, section: 'main' },
        { id: 'billing', label: 'Crédits', icon: Icons.Wallet, section: 'billing' },
        { id: 'subscriptions', label: 'Abonnements', icon: Icons.Card, section: 'billing' },
        { id: 'api-keys', label: 'Clés API', icon: Icons.Key, section: 'tools' },
        { id: 'settings', label: 'Paramètres', icon: Icons.Settings, section: 'tools' },
    ];
    const sections = {
        main: 'ESPACE PERSONNEL',
        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-white.svg" alt="Vocal" className="logo" />
                    <span className="sidebar-title">Mon Vocal</span>
                </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">
                    <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>
        </>
    );
};

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 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);
            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 || '',
            });
        } catch (e) { notify.error('Erreur chargement ligne'); }
        finally { setLoading(false); }
    }, [selectedLineId, notify]);

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

    const save = async () => {
        setSaving(true);
        try {
            const r = await api.put(`/my/lines/${selectedLineId}`, form);
            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 t = 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 ${t.color}`}>{t.label}</span>
                    </h1>
                    {line.label && <p className="page-subtitle">{line.label}</p>}
                </div>
                <div className="page-actions">
                    {tab === 'config' && !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: '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>
                            </>
                        )}
                        {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 === '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>
    );
};

// ==================== 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>
                                                                        <div style={{ color: 'var(--text-muted)', fontSize: '0.7rem', textTransform: 'uppercase', fontWeight: 600 }}>Enregistrement</div>
                                                                        <a href={call.recording_url} target="_blank" rel="noreferrer" className="btn btn-secondary btn-sm" style={{ fontSize: '0.75rem', padding: '0.2rem 0.5rem', marginTop: '0.3rem', display: 'inline-flex' }}>Écouter</a>
                                                                    </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: '' });
    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 || '',
                });
            } 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 }}>
                    <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>
        </>
    );
};

// ==================== 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">
                <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 === 'billing' && <BillingView />}
                {view === 'subscriptions' && <SubscriptionsView />}
                {view === 'api-keys' && <ApiKeysView />}
                {view === 'settings' && <SettingsView />}
            </div>
        </div>
    );
};

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