let socket = null;
let reconnectTimer = 0;
let reconnectAttempt = 0;
let stopped = false;
let handlers = null;

function clearReconnectTimer() {
  if (reconnectTimer) {
    clearTimeout(reconnectTimer);
    reconnectTimer = 0;
  }
}

function buildSocketUrl() {
  const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
  return `${protocol}//${window.location.host}/ws`;
}

function sendAuthHandshake() {
  if (!socket || socket.readyState !== WebSocket.OPEN) return;
  const token = localStorage.getItem("authToken");
  if (!token) return;
  socket.send(JSON.stringify({
    type: "auth",
    token,
  }));
}

function scheduleReconnect() {
  if (stopped) return;
  clearReconnectTimer();
  const delay = Math.min(10_000, 1_000 * 2 ** reconnectAttempt);
  reconnectAttempt += 1;
  reconnectTimer = window.setTimeout(() => {
    connect();
  }, delay);
}

function connect() {
  if (stopped) return;
  clearReconnectTimer();

  if (socket && (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING)) {
    return;
  }

  socket = new WebSocket(buildSocketUrl());

  socket.addEventListener("open", () => {
    reconnectAttempt = 0;
    sendAuthHandshake();
    handlers?.onOpen?.();
  });

  socket.addEventListener("message", (event) => {
    try {
      const data = JSON.parse(event.data);
      handlers?.onMessage?.(data);
    } catch {
      // ignore invalid payloads
    }
  });

  socket.addEventListener("close", () => {
    handlers?.onClose?.();
    scheduleReconnect();
  });

  socket.addEventListener("error", () => {
    // Let close handler trigger reconnect.
  });
}

export function startRealtime(nextHandlers = {}) {
  handlers = nextHandlers;
  stopped = false;
  connect();
}

export function restartRealtime() {
  if (stopped) return;
  if (socket) {
    try {
      socket.close();
    } catch {
      // ignore
    }
  }
  connect();
}

export function stopRealtime() {
  stopped = true;
  clearReconnectTimer();
  if (!socket) return;
  try {
    socket.close();
  } catch {
    // ignore
  }
  socket = null;
}

export function isRealtimeConnected() {
  return Boolean(socket && socket.readyState === WebSocket.OPEN);
}
