let socket = null;
let reconnectTimer = null;
let reconnectDelay = 1000;
let currentToken = null;
let currentHandlers = null;

function wsUrl(token) {
  const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
  const base = import.meta.env.BASE_URL || '/';
  const path = (base.endsWith('/') ? base : base + '/') + 'ws';
  // Path may start with /blocks/ in production. BASE_URL is '/blocks/' or '/'.
  const normalized = path.startsWith('/') ? path : '/' + path;
  return `${proto}//${location.host}${normalized}?token=${encodeURIComponent(token)}`;
}

export function sendWorkspace(state) {
  if (!socket || socket.readyState !== WebSocket.OPEN) return;
  try {
    socket.send(JSON.stringify({ type: 'workspace', state }));
  } catch { /* ignore */ }
}

function scheduleReconnect() {
  if (reconnectTimer) return;
  reconnectTimer = setTimeout(() => {
    reconnectTimer = null;
    if (currentToken && currentHandlers) openSocket();
  }, reconnectDelay);
  reconnectDelay = Math.min(reconnectDelay * 2, 15000);
}

function openSocket() {
  try {
    socket = new WebSocket(wsUrl(currentToken));
  } catch (err) {
    scheduleReconnect();
    return;
  }

  socket.addEventListener('open', () => {
    reconnectDelay = 1000;
    currentHandlers?.onOpen?.();
  });

  socket.addEventListener('message', (event) => {
    let msg;
    try { msg = JSON.parse(event.data); } catch { return; }
    if (!msg || typeof msg !== 'object') return;
    if (msg.type === 'push-code') {
      currentHandlers?.onPush?.(msg.state, msg.from);
    }
  });

  socket.addEventListener('close', () => {
    socket = null;
    currentHandlers?.onClose?.();
    if (currentToken) scheduleReconnect();
  });

  socket.addEventListener('error', () => {
    try { socket?.close(); } catch { /* ignore */ }
  });
}

export function connectStudent({ token, onPush, onOpen, onClose }) {
  disconnectStudent();
  currentToken = token;
  currentHandlers = { onPush, onOpen, onClose };
  reconnectDelay = 1000;
  openSocket();
}

export function disconnectStudent() {
  currentToken = null;
  currentHandlers = null;
  if (reconnectTimer) {
    clearTimeout(reconnectTimer);
    reconnectTimer = null;
  }
  if (socket) {
    try { socket.close(); } catch { /* ignore */ }
    socket = null;
  }
}

export function isStudentConnected() {
  return !!socket && socket.readyState === WebSocket.OPEN;
}
