import { getToken } from "./storage";

type MessageListener = (message: any) => void;

let activeWebSocket: WebSocket | null = null;
let reconnectTimeout: ReturnType<typeof setTimeout> | null = null;
let listeners: Set<MessageListener> = new Set();
let currentConfig: { enableReconnect?: boolean; reconnectDelay?: number } = {};

function connectWebSocket(): WebSocket | null {
  const token = getToken();
  if (!token) {
    return null;
  }

  if (activeWebSocket) {
    return activeWebSocket;
  }

  const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
  const wsUrl = `${protocol}//${window.location.host}/ws/sync?token=${token}`;
  const ws = new WebSocket(wsUrl);

  ws.onopen = () => {
    console.log("WebSocket connected");
  };

  ws.onmessage = (event: MessageEvent) => {
    try {
      const message = JSON.parse(event.data);
      listeners.forEach((listener) => {
        try {
          listener(message);
        } catch (error) {
          console.error("Error in WebSocket listener:", error);
        }
      });
    } catch (error) {
      console.error("Error parsing WebSocket message:", error);
    }
  };

  ws.onerror = (error: Event) => {
    console.error("WebSocket error:", error);
  };

  ws.onclose = () => {
    console.log("WebSocket disconnected");
    activeWebSocket = null;

    if (currentConfig.enableReconnect !== false) {
      const delay = currentConfig.reconnectDelay || 5000;
      console.log(`Reconnecting in ${delay / 1000}s...`);
      reconnectTimeout = setTimeout(() => {
        connectWebSocket();
      }, delay);
    }
  };

  activeWebSocket = ws;
  return ws;
}

function addListener(listener: MessageListener): void {
  listeners.add(listener);
  if (!activeWebSocket) {
    connectWebSocket();
  }
}

function removeListener(listener: MessageListener): void {
  listeners.delete(listener);
  if (listeners.size === 0) {
    disconnectWebSocket();
  }
}

function disconnectWebSocket(): void {
  if (reconnectTimeout) {
    clearTimeout(reconnectTimeout);
    reconnectTimeout = null;
  }
  if (activeWebSocket) {
    activeWebSocket.close();
    activeWebSocket = null;
  }
}

function createWebSocket(config: {
  onMessage: (data: any) => void;
  onOpen?: () => void;
  onClose?: () => void;
  onError?: (error: Event) => void;
  enableReconnect?: boolean;
  reconnectDelay?: number;
}): WebSocket | null {
  currentConfig = config;

  const listener: MessageListener = (message) => {
    config.onMessage(message);
  };

  listeners.add(listener);

  if (activeWebSocket) {
    activeWebSocket.close();
    activeWebSocket = null;
  }

  const ws = connectWebSocket();

  if (ws && config.onOpen) {
    if (ws.readyState === WebSocket.OPEN) {
      config.onOpen();
    } else {
      ws.addEventListener("open", () => config.onOpen?.(), { once: true });
    }
  }

  return ws;
}

export {
  addListener,
  createWebSocket,
  disconnectWebSocket,
  removeListener,
};
