import { defineStore } from "pinia";
import { ref } from "vue";

/**
 * WebSocket Store（浏览器端）
 * 与商家端 @/store/websocket 消息格式一致，用于分享动态、聊天等
 */
export const useWebSocketStore = defineStore("websocket", () => {
  const socket = ref<WebSocket | null>(null);
  const isConnected = ref(false);
  const isConnecting = ref(false);
  const lastConnectedUrl = ref("");

  // 消息订阅（用于聊天等）
  const messageHandlers = new Map<string, Array<(msg: any) => void>>();

  /** 以底层 readyState 为准，避免 isConnected 与真实连接短暂不一致 */
  const isSocketOpen = () => !!socket.value && socket.value.readyState === WebSocket.OPEN;

  /** 上一笔尚未结束的 connect 的 resolve；刷新时 Header 与聊天页并发 connect 会顶替，必须结束旧 Promise */
  let pendingConnectResolve: ((ok: boolean) => void) | null = null;

  const connect = (url: string): Promise<boolean> => {
    if (isSocketOpen() && lastConnectedUrl.value === url) {
      isConnected.value = true;
      return Promise.resolve(true);
    }
    if (pendingConnectResolve) {
      const prev = pendingConnectResolve;
      pendingConnectResolve = null;
      prev(false);
    }
    if (socket.value) {
      try {
        socket.value.close();
      } catch (e) {
        console.warn("关闭旧连接失败:", e);
      }
      socket.value = null;
      isConnected.value = false;
    }

    isConnecting.value = true;
    lastConnectedUrl.value = url;

    return new Promise(resolve => {
      pendingConnectResolve = resolve;
      const settle = (ok: boolean) => {
        if (pendingConnectResolve === resolve) {
          pendingConnectResolve = null;
          resolve(ok);
        }
      };

      try {
        const ws = new WebSocket(url);
        socket.value = ws;

        ws.onopen = () => {
          if (socket.value !== ws) return;
          isConnected.value = true;
          isConnecting.value = false;
          settle(true);
        };

        ws.onmessage = (event: MessageEvent) => {
          if (socket.value !== ws) return;
          try {
            const message = JSON.parse(event.data);
            const category = message.category || "message";
            // 按 category 分发
            const handlers = messageHandlers.get(category);
            if (handlers?.length) {
              handlers.forEach(cb => cb(message));
            }
            // 兼容：若后端推送的 category 不是 "message" 但明显是聊天消息，也派发给 message 订阅者（解决业主发消息不实时更新）
            const isChatLike =
              category !== "message" &&
              (message.senderId != null || message.receiverId != null) &&
              (message.text != null || message.content != null || message.type != null);
            if (isChatLike) {
              const messageHandlersList = messageHandlers.get("message");
              if (messageHandlersList?.length) {
                messageHandlersList.forEach(cb => cb(message));
              }
            }
          } catch (_) {}
        };

        ws.onclose = () => {
          // 必须校验实例：新 connect 关闭旧 socket 后，旧 onclose 仍会触发，否则会清空新连接导致「刷新后必现失败」
          if (socket.value !== ws) return;
          isConnected.value = false;
          isConnecting.value = false;
          socket.value = null;
          // 握手未完成即关闭时结束 Promise（若已成功 onopen 已 settle，此处不再 resolve）
          settle(false);
        };

        ws.onerror = () => {
          if (socket.value !== ws) return;
          isConnected.value = false;
          isConnecting.value = false;
          socket.value = null;
          settle(false);
        };
      } catch (e) {
        console.error("WebSocket 连接异常:", e);
        isConnecting.value = false;
        settle(false);
      }
    });
  };

  /** 订阅消息（返回取消订阅函数） */
  const subscribe = (type: string, callback: (msg: any) => void) => {
    if (!messageHandlers.has(type)) {
      messageHandlers.set(type, []);
    }
    messageHandlers.get(type)!.push(callback);
    return () => {
      const handlers = messageHandlers.get(type) || [];
      messageHandlers.set(
        type,
        handlers.filter(h => h !== callback)
      );
    };
  };

  const sendMessage = (data: Record<string, unknown>): Promise<boolean> => {
    return new Promise(resolve => {
      if (!isSocketOpen()) {
        if (isConnected.value) isConnected.value = false;
        console.warn("WebSocket 未连接，无法发送消息");
        resolve(false);
        return;
      }
      try {
        const message = JSON.stringify(data);
        socket.value.send(message);
        resolve(true);
      } catch (e) {
        console.error("消息发送异常:", e);
        resolve(false);
      }
    });
  };

  const disconnect = () => {
    if (socket.value) {
      try {
        socket.value.close();
      } catch (_) {}
      socket.value = null;
    }
    isConnected.value = false;
    isConnecting.value = false;
    lastConnectedUrl.value = "";
    messageHandlers.clear();
  };

  return {
    socket,
    isConnected,
    isConnecting,
    lastConnectedUrl,
    isSocketOpen,
    connect,
    sendMessage,
    disconnect,
    subscribe
  };
});
