import { BASE_URL } from "../../api/request";
import { getToken } from "../until";

let ws = null;
let reconnectTimer = null;
let manualClose = false;
let retryCount = 0;
const subscribers = new Set();

const WS_PATH = "/ws";
const MAX_RECONNECT_DELAY = 30000;

function getWsBaseUrl() {
  const baseApi = import.meta.env.VITE_APP_BASE_API || "";

  if (/^https?:\/\//.test(baseApi)) {
    return baseApi.replace(/^http/, "ws").replace(/\/$/, "");
  }

  // UniApp 没有 window，用 uni 接口获取
  const platform = uni.getSystemInfoSync().platform;
  const isH5 = platform === "h5";
  const protocol =
    isH5 && window.location.protocol === "https:" ? "wss:" : "ws:";

  let host = "";
  if (isH5) {
    host = window.location.host;
  } else {
    // 非H5（小程序/App）需要你配置真实域名
    host = BASE_URL;
  }

  return `${protocol}//${host}${baseApi}`.replace(/\/$/, "");
}

function buildWsUrl() {
  const baseUrl = getWsBaseUrl();
  const url = `${baseUrl}${WS_PATH}`;
  const token = getToken();

  const params = new URLSearchParams();
  if (token) {
    params.append("token", token);
  }

  const query = params.toString();
  return query ? `${url}?${query}` : url;
}

export function connectWs(onMessage) {
  if (!getToken()) {
    console.warn("[WebSocket] missing token");
    return;
  }

  if (typeof onMessage === "function") {
    subscribers.add(onMessage);
  }

  manualClose = false;
  clearReconnectTimer();

  if (ws) {
    return;
  }

  // ========== UniApp 专用 ==========
  ws = uni.connectSocket({
    url: buildWsUrl(),
    success: () => {},
  });

  ws.onOpen = () => {
    retryCount = 0;
    console.log("[WebSocket] connected");
  };

  ws.onMessage = (event) => {
    let data = event.data;
    try {
      data = JSON.parse(event.data);
    } catch (e) {}

    subscribers.forEach((handler) => {
      try {
        handler(data, event);
      } catch (error) {
        console.error("[WebSocket] subscriber error", error);
      }
    });
  };

  ws.onClose = () => {
    console.log("[WebSocket] closed");
    ws = null;

    if (!manualClose && subscribers.size > 0) {
      reconnectTimer = setTimeout(() => {
        console.log("[WebSocket] reconnecting");
        connectWs();
      }, getReconnectDelay());
    }
  };

  ws.onError = (error) => {
    console.error("[WebSocket] error", error);
  };
}

export function closeWs(onMessage) {
  if (typeof onMessage === "function") {
    subscribers.delete(onMessage);
  } else {
    subscribers.clear();
  }

  if (subscribers.size > 0) {
    return;
  }

  manualClose = true;
  retryCount = 0;
  clearReconnectTimer();

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

export function reconnectWs(onMessage) {
  if (typeof onMessage === "function") {
    subscribers.add(onMessage);
  }

  manualClose = false;
  retryCount = 0;
  clearReconnectTimer();

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

  manualClose = false;
  connectWs();
}

export function sendWs(data) {
  if (!ws) {
    console.warn("[WebSocket] send failed, socket is not open");
    return false;
  }

  ws.send({
    data: typeof data === "string" ? data : JSON.stringify(data),
    success: () => {},
    fail: () => {},
  });
  return true;
}

export function getWsState() {
  if (!ws) return 3; // CLOSED
  return ws.readyState;
}

function getReconnectDelay() {
  retryCount += 1;
  return Math.min(5000 * retryCount, MAX_RECONNECT_DELAY);
}

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