// Tempo — Connecter un broker & importer un fichier (à insérer dans Réglages)
// ---------------------------------------------------------------------------
// Composant 100% FRONTEND. Aucune dépendance, aucun secret côté client.
//
// Architecture de sécurité (cf. SECURITY.md) :
//  - Le frontend NE détient AUCUN secret : ni service_role Supabase, ni token
//    MetaApi. Le mot de passe broker n'est JAMAIS conservé après l'envoi : il
//    transite (HTTPS) vers le Worker → MetaApi pour provisionner le compte en
//    LECTURE SEULE, puis on ne garde que l'accountId MetaApi côté Worker.
//  - Le mot de passe demandé est le MOT DE PASSE INVESTISSEUR (read-only) : il
//    ne permet pas de passer d'ordres. On le dit explicitement dans l'UI.
//  - Chaque appel au Worker porte le JWT Supabase de l'utilisateur
//    (Authorization: Bearer <access_token>). Le Worker le vérifie auprès de
//    /auth/v1/user AVANT toute action et n'agit que sur ce user_id.
//  - Le Worker écrit dans Supabase via service_role (secret Worker uniquement)
//    et n'appelle QUE des endpoints MetaApi de LECTURE (historique des deals).
//
// Endpoints attendus du Worker (tous JSON, tous protégés par le JWT) :
//   GET  {WORKER}/status      → { connections: [ { id, label, login, server,
//                                  status: 'ok'|'sync'|'error'|'pending',
//                                  last_sync_at, last_error, trade_count } ] }
//   POST {WORKER}/connect     body { login, password, server, label }
//   POST {WORKER}/sync        body { id }   (id optionnel → tout synchroniser)
//   POST {WORKER}/disconnect  body { id }
//
// Exposé : window.BrokerPanel (complet) + window.BrokerPanelCompact (réduit).

const BROKER_WORKER_DEFAULT = 'https://tempo-broker-sync.guillaume-briere92.workers.dev';

// ─── Helpers réseau (JWT-authentifiés) ────────────────────────────────────
// Récupère le JWT de session Supabase. Sans session → on refuse l'appel.
async function _brokerAccessToken() {
  if (!window.sb) return null;
  try {
    const { data } = await window.sb.auth.getSession();
    return data?.session?.access_token || null;
  } catch (e) { return null; }
}

// Appel générique au Worker. Renvoie { data } ou { error: { message } } (FR).
// `worker` = base URL (sans slash final), `path` = '/status' etc.
async function _brokerCall(worker, path, { method = 'GET', body } = {}) {
  const token = await _brokerAccessToken();
  if (!token) return { error: { message: 'Tu dois être connecté pour gérer un broker.' } };
  const base = String(worker || BROKER_WORKER_DEFAULT).replace(/\/+$/, '');
  let res;
  try {
    res = await fetch(base + path, {
      method,
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + token,
      },
      body: body ? JSON.stringify(body) : undefined,
    });
  } catch (e) {
    return { error: { message: 'Connexion au service impossible — vérifie ta connexion internet et réessaie.' } };
  }
  // Essaie de lire un corps JSON ; tolère une réponse vide.
  let payload = null;
  try { payload = await res.json(); } catch (e) { payload = null; }
  if (!res.ok) {
    const raw = (payload && (payload.error || payload.message)) || '';
    return { error: { message: _brokerFrError(raw, res.status) } };
  }
  return { data: payload || {} };
}

// Mappe les erreurs serveur/broker connues vers des messages FR propres.
function _brokerFrError(raw, status) {
  const m = String(raw || '').toLowerCase();
  if (status === 401 || status === 403 || /unauthor|forbidden|invalid token|jwt/.test(m))
    return 'Session expirée — reconnecte-toi puis réessaie.';
  if (/invalid (account|login|credential)|auth.*fail|wrong password|password/.test(m))
    return 'Identifiants refusés par le broker. Vérifie le numéro de compte, le mot de passe investisseur et le serveur.';
  if (/server.*not.*found|unknown server|invalid server|resolve/.test(m))
    return 'Serveur du broker introuvable. Copie le nom EXACT depuis MetaTrader (menu Outils → Options → Serveur).';
  if (/already.*(connect|exist)|duplicate/.test(m))
    return 'Ce compte est déjà connecté.';
  if (/timeout|timed out|deadline/.test(m))
    return 'Le broker met trop de temps à répondre. Réessaie dans un instant.';
  if (/rate.?limit|too many/.test(m))
    return 'Trop de tentatives — patiente quelques minutes avant de réessayer.';
  if (status >= 500)
    return 'Le service de synchronisation est momentanément indisponible. Réessaie dans quelques minutes.';
  return (raw && String(raw)) || 'Une erreur est survenue. Réessaie.';
}

// Date de dernière synchro → libellé court FR (réutilise fmtShortDate global).
function _brokerSyncLabel(iso) {
  if (!iso) return 'Jamais synchronisé';
  if (typeof fmtShortDate === 'function') {
    const s = fmtShortDate(iso);
    return s === '—' ? 'Jamais synchronisé' : ('Dernière synchro · ' + s);
  }
  return 'Dernière synchro · ' + String(iso).slice(0, 16).replace('T', ' ');
}

// Métadonnées d'affichage d'un statut de connexion.
function _brokerStatusMeta(status) {
  switch (String(status || '').toLowerCase()) {
    case 'ok':      return { label: 'Connecté',         tone: 'green' };
    case 'sync':
    case 'syncing': return { label: 'Synchronisation…', tone: 'blue'  };
    case 'pending': return { label: 'En attente…',      tone: 'blue'  };
    case 'error':   return { label: 'Erreur',           tone: 'red'   };
    default:        return { label: 'Inconnu',          tone: 'gray'  };
  }
}

// Petit point de statut coloré (pulsé quand la synchro est en cours).
function _BrokerDot({ tone }) {
  const color = tone === 'green' ? 'var(--green)'
    : tone === 'red' ? 'var(--red)'
    : tone === 'blue' ? 'var(--blue)'
    : 'var(--fg-4)';
  return (
    <span style={{
      width: 8, height: 8, borderRadius: 999, background: color, color,
      display: 'inline-block', flexShrink: 0,
      animation: tone === 'blue' ? 'pulse-dot 1.4s var(--ease) infinite' : 'none',
    }}/>
  );
}

// Pastille de statut (texte + point).
function _BrokerStatusPill({ status }) {
  const meta = _brokerStatusMeta(status);
  const bg = meta.tone === 'green' ? 'var(--green-soft)'
    : meta.tone === 'red' ? 'var(--red-soft)'
    : meta.tone === 'blue' ? 'var(--blue-soft)'
    : 'var(--bg-elev)';
  const fg = meta.tone === 'green' ? 'var(--green-text)'
    : meta.tone === 'red' ? 'var(--red-text)'
    : meta.tone === 'blue' ? 'var(--blue-600)'
    : 'var(--fg-2)';
  return (
    <span className="pill" style={{ background: bg, color: fg, border: '1px solid var(--line)', padding: '4px 10px', fontSize: 11.5, fontWeight: 600 }}>
      <_BrokerDot tone={meta.tone}/>
      {meta.label}
    </span>
  );
}

// ─── Carte d'une connexion existante ──────────────────────────────────────
function _BrokerConnectionCard({ conn, worker, onChanged }) {
  const [busy, setBusy] = React.useState(null); // 'sync' | 'disconnect' | null
  const [err, setErr]   = React.useState('');
  const meta = _brokerStatusMeta(conn.status);

  const doSync = async () => {
    if (busy) return;
    setBusy('sync'); setErr('');
    const r = await _brokerCall(worker, '/sync', { method: 'POST', body: { connectionId: conn.id } });
    setBusy(null);
    if (r.error) { setErr(r.error.message); return; }
    onChanged && onChanged({ synced: true });
  };

  const doDisconnect = async () => {
    if (busy) return;
    setBusy('disconnect'); setErr('');
    const r = await _brokerCall(worker, '/disconnect', { method: 'POST', body: { connectionId: conn.id } });
    setBusy(null);
    if (r.error) { setErr(r.error.message); return; }
    onChanged && onChanged({ disconnected: true });
  };

  const login = conn.login || conn.account || '';
  const title = conn.label || (login ? 'Compte ' + login : 'Compte MetaTrader 5');

  return (
    <div className="card" style={{ padding: '16px 18px', display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12 }}>
        <div style={{ minWidth: 0 }}>
          <div style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-.01em', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
            {title}
          </div>
          <div style={{ fontSize: 11.5, color: 'var(--fg-3)', marginTop: 3 }}>
            {login ? ('MT5 · n° ' + login) : 'MetaTrader 5'}
            {conn.server ? ' · ' + conn.server : ''}
          </div>
        </div>
        <_BrokerStatusPill status={conn.status}/>
      </div>

      <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11.5, color: 'var(--fg-3)' }}>
        <span>{_brokerSyncLabel(conn.last_sync_at)}</span>
      </div>

      {meta.tone === 'red' && conn.last_error && (
        <div style={{ fontSize: 11.5, color: 'var(--red-text)', background: 'var(--red-soft)', border: '1px solid var(--line)', borderRadius: 8, padding: '8px 10px', lineHeight: 1.45 }}>
          {conn.last_error}
        </div>
      )}

      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
        <button onClick={doSync} disabled={!!busy} className="btn btn-outline-blue tap" style={{ opacity: busy ? 0.7 : 1 }}>
          {Ico.sync} {busy === 'sync' ? 'Synchronisation…' : 'Synchroniser maintenant'}
        </button>
        <button onClick={doDisconnect} disabled={!!busy} className="btn tap"
          style={{ color: 'var(--red)', borderColor: 'var(--line)', opacity: busy ? 0.7 : 1 }}>
          {busy === 'disconnect' ? 'Déconnexion…' : 'Déconnecter'}
        </button>
      </div>

      {err && <div style={{ fontSize: 12, color: 'var(--red)' }}>{err}</div>}
    </div>
  );
}

// ─── Formulaire « Connecter MetaTrader 5 » ────────────────────────────────
function _BrokerConnectForm({ worker, onConnected }) {
  const [login, setLogin]   = React.useState('');
  const [pwd, setPwd]       = React.useState('');
  const [server, setServer] = React.useState('');
  const [label, setLabel]   = React.useState('');
  const [showPwd, setShowPwd] = React.useState(false);
  const [busy, setBusy]     = React.useState(false);
  const [err, setErr]       = React.useState('');
  const [ok, setOk]         = React.useState(false);

  const labelStyle = { fontSize: 11, fontWeight: 600, color: 'var(--fg-3)', letterSpacing: '.04em', textTransform: 'uppercase', marginBottom: 6, display: 'block' };

  const valid = login.trim() && pwd.trim() && server.trim();

  const submit = async () => {
    if (busy || !valid) return;
    setBusy(true); setErr(''); setOk(false);
    const body = {
      login: login.trim(),
      password: pwd,            // transite vers MetaApi ; jamais stocké côté client
      server: server.trim(),
      label: label.trim() || null,
    };
    const r = await _brokerCall(worker, '/connect', { method: 'POST', body });
    // Sécurité : on efface le mot de passe de la mémoire dès la réponse,
    // succès comme échec.
    setPwd('');
    setBusy(false);
    if (r.error) { setErr(r.error.message); return; }
    setOk(true);
    setLogin(''); setServer(''); setLabel(''); setShowPwd(false);
    onConnected && onConnected();
    setTimeout(() => setOk(false), 2500);
  };

  return (
    <div className="card" style={{ padding: '20px 22px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
        {Ico.connections}
        <div style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-.01em' }}>Connecter MetaTrader 5</div>
      </div>
      <p style={{ fontSize: 12, color: 'var(--fg-3)', margin: '0 0 16px', lineHeight: 1.5 }}>
        Tes trades clôturés sont importés automatiquement, sans copier-coller. La synchro
        est en lecture seule : Tempo ne peut jamais passer d'ordre à ta place.
      </p>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 12 }}>
        <div>
          <label style={labelStyle}>Numéro de compte</label>
          <input className="input" value={login} onChange={e => setLogin(e.target.value)}
            inputMode="numeric" autoComplete="off" placeholder="Ex. 51234567" disabled={busy}/>
        </div>
        <div>
          <label style={labelStyle}>Serveur du broker</label>
          <input className="input" value={server} onChange={e => setServer(e.target.value)}
            autoComplete="off" placeholder="Ex. ICMarketsSC-Demo" disabled={busy}/>
        </div>
      </div>

      <div style={{ marginBottom: 8 }}>
        <label style={labelStyle}>Mot de passe investisseur (lecture seule)</label>
        <div style={{ position: 'relative' }}>
          <input className="input" type={showPwd ? 'text' : 'password'} value={pwd}
            onChange={e => setPwd(e.target.value)} autoComplete="new-password"
            placeholder="Mot de passe investisseur" disabled={busy}
            style={{ paddingRight: 64 }}/>
          <button type="button" onClick={() => setShowPwd(s => !s)} disabled={busy} className="tap"
            style={{ position: 'absolute', right: 6, top: '50%', transform: 'translateY(-50%)',
              background: 'transparent', border: 'none', cursor: 'pointer',
              color: 'var(--fg-3)', fontSize: 11.5, fontWeight: 600, padding: '4px 6px' }}>
            {showPwd ? 'Masquer' : 'Afficher'}
          </button>
        </div>
      </div>

      <div style={{ display: 'flex', gap: 8, alignItems: 'flex-start', fontSize: 11.5, color: 'var(--fg-3)', background: 'var(--bg-soft)', border: '1px solid var(--line)', borderRadius: 8, padding: '9px 11px', marginBottom: 14, lineHeight: 1.5 }}>
        {Ico.risk}
        <span>
          Utilise bien le mot de passe <b style={{ color: 'var(--fg-2)' }}>investisseur</b> (read-only) —
          il ne permet pas de trader. Tempo ne le stocke jamais : il sert seulement à
          provisionner la connexion en lecture chez notre prestataire de synchronisation, en HTTPS.
        </span>
      </div>

      <div style={{ marginBottom: 16 }}>
        <label style={labelStyle}>Libellé (optionnel)</label>
        <input className="input" value={label} onChange={e => setLabel(e.target.value)}
          autoComplete="off" placeholder="Ex. Compte FTMO 100k" disabled={busy}/>
      </div>

      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <button onClick={submit} disabled={busy || !valid} className="btn btn-blue tap"
          style={{ opacity: (busy || !valid) ? 0.55 : 1, cursor: (busy || !valid) ? 'not-allowed' : 'pointer' }}>
          {busy ? 'Connexion…' : 'Connecter'}
        </button>
        {ok && <span style={{ fontSize: 12.5, color: 'var(--green)', fontWeight: 600 }}>Compte connecté ✓</span>}
        {err && <span style={{ fontSize: 12.5, color: 'var(--red)' }}>{err}</span>}
      </div>
    </div>
  );
}

// ─── Zone « Importer un fichier (CSV / HTML) » ────────────────────────────
// Réutilise TOUJOURS le flux d'import manuel existant via onImportFile/openImport.
function _BrokerImportZone({ onImportFile, openImport }) {
  const open = onImportFile || openImport;
  return (
    <div className="card" style={{ padding: '20px 22px', display: 'flex', alignItems: 'flex-start', gap: 14, flexWrap: 'wrap' }}>
      <div style={{ flex: 1, minWidth: 200 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
          {Ico.upload}
          <div style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-.01em' }}>Importer un fichier (CSV / HTML)</div>
        </div>
        <p style={{ fontSize: 12, color: 'var(--fg-3)', margin: 0, lineHeight: 1.5 }}>
          Pas de connexion auto ? Importe ton relevé MetaTrader 5 ou tout export CSV.
          Disponible à tout moment, en complément de la synchronisation.
        </p>
      </div>
      <button onClick={() => open && open()} className="btn tap" disabled={!open}
        style={{ alignSelf: 'center', opacity: open ? 1 : 0.5 }}>
        {Ico.upload} Importer un fichier
      </button>
    </div>
  );
}

// ─── Panneau principal ────────────────────────────────────────────────────
// Props :
//   worker        : URL du Worker (défaut BROKER_WORKER_DEFAULT)
//   onSynced      : callback appelé après une synchro/connexion réussie
//                   (l'intégration y branche state.refreshTrades())
//   onImportFile / openImport : ouvre le flux d'import fichier existant
//   compact       : rendu réduit (cf. BrokerPanelCompact)
function BrokerPanel({ worker, onSynced, onImportFile, openImport, compact = false }) {
  const WORKER = worker || BROKER_WORKER_DEFAULT;
  const [conns, setConns]     = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [loadErr, setLoadErr] = React.useState('');
  const liveRef = React.useRef(true);

  const loadStatus = React.useCallback(async () => {
    setLoading(true); setLoadErr('');
    const r = await _brokerCall(WORKER, '/status', { method: 'GET' });
    if (!liveRef.current) return;
    setLoading(false);
    if (r.error) { setLoadErr(r.error.message); setConns([]); return; }
    const list = (r.data && (r.data.connections || r.data.items)) || [];
    setConns(Array.isArray(list) ? list : []);
  }, [WORKER]);

  React.useEffect(() => {
    liveRef.current = true;
    loadStatus();
    return () => { liveRef.current = false; };
  }, [loadStatus]);

  // Après une action réussie : on recharge le statut ET on prévient l'app
  // (rechargement des trades via onSynced).
  const handleChanged = async () => {
    await loadStatus();
    if (typeof onSynced === 'function') { try { await onSynced(); } catch (e) {} }
  };

  const hasConns = conns.length > 0;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: compact ? 12 : 14 }}>
      {/* État des connexions */}
      {loading ? (
        <div className="card" style={{ padding: '24px 22px', textAlign: 'center', fontSize: 12.5, color: 'var(--fg-3)' }}>
          Chargement des connexions…
        </div>
      ) : loadErr ? (
        <div className="card" style={{ padding: '18px 20px', borderColor: 'var(--line)' }}>
          <div style={{ fontSize: 12.5, color: 'var(--red-text)', marginBottom: 10 }}>{loadErr}</div>
          <button onClick={loadStatus} className="btn tap">{Ico.refresh} Réessayer</button>
        </div>
      ) : hasConns ? (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {conns.map((c, i) => (
            <_BrokerConnectionCard key={c.id || c.login || i} conn={c} worker={WORKER} onChanged={handleChanged}/>
          ))}
        </div>
      ) : (
        <div className="card" style={{ padding: '18px 20px', display: 'flex', alignItems: 'center', gap: 12 }}>
          {Ico.connections}
          <div style={{ fontSize: 12.5, color: 'var(--fg-2)', lineHeight: 1.5 }}>
            Aucun broker connecté pour l'instant. Connecte ton compte ci-dessous pour importer
            tes trades automatiquement.
          </div>
        </div>
      )}

      {/* Formulaire de connexion MT5 */}
      <_BrokerConnectForm worker={WORKER} onConnected={handleChanged}/>

      {/* Import fichier — toujours disponible */}
      <_BrokerImportZone onImportFile={onImportFile} openImport={openImport}/>

      {/* Note Futures / Tradovate */}
      <div style={{ fontSize: 11.5, color: 'var(--fg-4)', lineHeight: 1.5, padding: '2px 2px 0' }}>
        Futures (Tradovate) : bientôt — pour l'instant, importe ton relevé en CSV.
      </div>
    </div>
  );
}

// Version compacte : même contenu, simplement un wrapper sémantique pour les
// intégrations mobiles / encarts réduits. (Le rendu interne s'adapte déjà.)
function BrokerPanelCompact(props) {
  return <BrokerPanel {...props} compact={true}/>;
}

Object.assign(window, { BrokerPanel, BrokerPanelCompact, BROKER_WORKER_DEFAULT });
