/* eslint-disable no-console */
/* eslint-disable unicorn/prefer-add-event-listener */
import { ref } from 'vue';

import { useMessage } from '@jnpf/hooks';

import { useAppConfig } from '@vben/hooks';
import { useAccessStore, useUserStore } from '@vben/stores';

import ReconnectingWebSocket from 'reconnecting-websocket';

import { $t } from '#/locales';
import { useAuthStore } from '#/store';
import { getRealJnpfAppEnCode } from '#/utils/jnpf';

const userStore = useUserStore();
const userInfo = userStore.getUserInfo;
const { createMessage, createWarningModal } = useMessage();
const { isDevMode, webSocketURL } = useAppConfig(import.meta.env, import.meta.env.PROD);

const url = isDevMode() ? `${webSocketURL}/api/message/websocket/` : webSocketURL ? `${webSocketURL}/websocket/` : `${window.location.origin}/websocket/`;
const webSocketUrl = url.replace('https://', 'wss://').replace('http://', 'ws://');

let ws: any;
const listeners = new Map();

export function useWebSocket() {
  const accessStore = useAccessStore();
  const authStore = useAuthStore();
  const token = accessStore.accessToken;
  const server = ref(webSocketUrl + encodeURIComponent(token as string));
  /** 初始化WebSocket */
  function initWebSocket() {
    if (ws) {
      ws.close();
      ws = null;
    }
    ws = new ReconnectingWebSocket(server.value);

    ws.addEventListener('open', onOpen);
    ws.onerror = onError;
    ws.onmessage = onMessage;

    function onOpen() {
      const onConnection = { method: 'OnConnection', mobileDevice: false, systemId: userInfo?.systemId, isSeparate: !!getRealJnpfAppEnCode() };
      sendWsMsg(JSON.stringify(onConnection));
    }

    function onError(e) {
      console.log('[WebSocket] 连接发生错误:', e);
    }

    function onMessage(res) {
      if (res.data) {
        try {
          const dataStr = res.data;
          const data = JSON.parse(dataStr);
          for (const callback of listeners.keys()) {
            try {
              callback(data);
            } catch (error) {
              console.error(error);
            }
          }
          // initMessage: //初始化
          // sendMessage: //发送消息
          // receiveMessage: //接收消息
          // messageList: //消息列表
          // messagePush: //消息推送
          switch (data.method) {
            // 断开websocket连接
            case 'closeSocket': {
              if (ws) {
                ws.close();
                ws = null;
              }
              break;
            }
            // 用户过期
            case 'logout': {
              if (data.token && data.token !== token) return location.reload();
              if (ws) {
                ws.close();
                ws = null;
              }
              createMessage.error(data.msg || '登录过期,请重新登录').then(() => {
                accessStore.setAccessToken(null);
                authStore.logout();
              });
              break;
            }
            // 刷新页面
            case 'refresh': {
              createWarningModal({
                title: $t('common.tipTitle'),
                content: data.msg || '您的权限发生变更，请刷新界面！',
                okText: '刷新',
                onOk: () => {
                  location.reload();
                },
              });
              break;
            }
            default: {
              break;
            }
          }
        } catch (error) {
          console.error('[WebSocket] data解析失败：', error);
        }
      }
    }
  }
  /**
   * 添加 WebSocket 消息监听
   * @param callback
   */
  function onWebSocket(callback: (data: object) => any) {
    if (!listeners.has(callback)) {
      if (typeof callback === 'function') {
        listeners.set(callback, null);
      } else {
        console.debug('[WebSocket] 添加 WebSocket 消息监听失败：传入的参数不是一个方法');
      }
    }
  }

  /**
   * 解除 WebSocket 消息监听
   *
   * @param callback
   */
  function offWebSocket(callback: (data: object) => any) {
    listeners.delete(callback);
  }

  function getWebSocket() {
    return ws;
  }

  function sendWsMsg(msg: string) {
    try {
      const msgObj = JSON.parse(msg);
      msgObj.token = token;
      const content = JSON.stringify(msgObj);
      ws.send(content);
    } catch {}
  }

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

  return {
    initWebSocket,
    sendWsMsg,
    onWebSocket,
    offWebSocket,
    getWebSocket,
    closeWebSocket,
  };
}
