// Micara bridge — client signaling WebSocket (app silencieuse)
// Maintient la connexion /ws?token=…&role=bridge avec reconnexion auto
// (backoff exponentiel). Le renderer reçoit les messages via onMessage et
// répond via send() (relais IPC du main). WebSocket global (Electron 43 /
// Node 22) injectable pour les tests.
function createBridgeClient({ wsUrl, WebSocketImpl = globalThis.WebSocket, onStatus, onMessage, maxBackoffMs = 30_000 }) {
  let ws = null;
  let closed = false;
  let backoffMs = 1_000;
  let retryTimer = null;

  function connect() {
    if (closed) return;
    onStatus && onStatus('connecting');
    let w;
    try {
      w = new WebSocketImpl(wsUrl);
    } catch (e) {
      onStatus && onStatus('disconnected');
      schedule();
      return;
    }
    ws = w;
    w.onopen = () => {
      backoffMs = 1_000;
      onStatus && onStatus('connected');
    };
    w.onmessage = (ev) => {
      if (!onMessage) return;
      try { onMessage(JSON.parse(ev.data)); } catch { /* message non JSON ignoré */ }
    };
    w.onclose = () => {
      if (ws === w) ws = null;
      onStatus && onStatus('disconnected');
      schedule();
    };
    w.onerror = () => {
      try { w.close(); } catch { /* close() déclenchera onclose */ }
    };
  }

  function schedule() {
    if (closed) return;
    clearTimeout(retryTimer);
    retryTimer = setTimeout(() => {
      backoffMs = Math.min(backoffMs * 2, maxBackoffMs);
      connect();
    }, backoffMs);
  }

  return {
    connect,
    send: (obj) => {
      if (ws && ws.readyState === 1) {
        ws.send(JSON.stringify(obj));
        return true;
      }
      return false; // signal pas prêt → le renderer re-offrira au prochain connect
    },
    close: () => {
      closed = true;
      clearTimeout(retryTimer);
      try { if (ws) ws.close(); } catch { /* déjà fermé */ }
      ws = null;
    },
    get ready() {
      return !!(ws && ws.readyState === 1);
    },
  };
}

module.exports = { createBridgeClient };
