// 自己定义的 websocket, 使用时注意
import { useGlobSetting } from '../setting';
import { useUserStoreWithOut } from '/@/store/modules/user';
import { getAuthCache } from '../../utils/auth';
import { LOGINTYPE_KEY, TOKEN_KEY } from '../../enums/cacheEnum';
import { ref } from 'vue';
import { useIntervalFn } from '@vueuse/core';
import { useMessage } from './useMessage';
import { ResultEnum } from '/@/enums/httpEnum';

function resolveNestedOptions<T>(options: T | true): T {
  if (options === true) return {} as T;
  return options;
}
export type WebSocketStatus = 'OPEN' | 'CONNECTING' | 'CLOSED';

export default function useWebSocketFn() {
  const { createMessage } = useMessage();
  const { websocketUrl } = useGlobSetting();
  const userStore = useUserStoreWithOut();

  let token = undefined;
  let loginType = undefined;

  const wsRef = ref<WebSocket | undefined>();
  const status = ref<WebSocketStatus>('CLOSED');
  const data = ref<any>(null);
  const DEFAULT_PING_MESSAGE = 'ping';
  let pongTimeoutWait: ReturnType<typeof setTimeout> | undefined;
  let bufferedData: (string | ArrayBuffer | Blob)[] = [];
  let heartbeatResume: Fn | undefined;
  let heartbeatPause: Fn | undefined;

  const heartbeat = {
    interval: 1000 * 10,
    message: JSON.stringify({ s: '2' }),
    pongTimeout: 1000 * 30,
  };

  // 是否可以连接
  const boolCondition = (): Boolean => {
    token = getAuthCache(TOKEN_KEY);
    loginType = getAuthCache(LOGINTYPE_KEY);
    if (token == '' || token == undefined || loginType == undefined || loginType == '') {
      return false;
    } else {
      return true;
    }
  };

  const resetHeartbeat = () => {
    clearTimeout(pongTimeoutWait);
    pongTimeoutWait = undefined;
  };

  const _sendBuffer = () => {
    if (bufferedData.length && wsRef.value && status.value === 'OPEN') {
      for (const buffer of bufferedData) wsRef.value.send(buffer);
      bufferedData = [];
    }
  };

  const send = (data: string | ArrayBuffer | Blob, useBuffer = true) => {
    if (!wsRef.value || status.value !== 'OPEN') {
      if (useBuffer) bufferedData.push(data);
      return false;
    }
    _sendBuffer();
    wsRef.value.send(data);
    return true;
  };

  const close: WebSocket['close'] = (code = 1000, reason) => {
    if (!wsRef.value) return;
    heartbeatPause?.();
    wsRef.value.close(code, reason);
  };

  const _init = () => {
    const isWebscoket = boolCondition();
    if (!isWebscoket) return;
    const params = `?Authorization=${token}&LoginType=${loginType}`;
    // 设置 websocket 连接地址
    const setWebsocketUrl = `${websocketUrl + params}`;
    const ws = new WebSocket(setWebsocketUrl);
    wsRef.value = ws;
    status.value = 'CONNECTING';

    if (heartbeat) {
      const {
        message = DEFAULT_PING_MESSAGE,
        interval = 1000,
        pongTimeout = 1000,
      } = resolveNestedOptions(heartbeat);

      const { pause, resume } = useIntervalFn(
        () => {
          send(message, false);
          if (pongTimeoutWait != null) return;
          pongTimeoutWait = setTimeout(() => {
            console.log('是否关闭');
            // auto-reconnect will be trigger with ws.onclose()
            close();
          }, pongTimeout);
        },
        interval,
        { immediate: false },
      );
      heartbeatPause = pause;
      heartbeatResume = resume;
    }

    // 监听是否连接成功
    ws.onopen = () => {
      status.value = 'OPEN';
      // console.log('ws连接状态：' + ws.readyState);
      heartbeatResume?.();
      _sendBuffer();
    };

    //接听服务器发回的信息并处理展示
    ws.onmessage = async function (e) {
      // console.log('接收到来自服务器的消息：', e);
      // console.log('status', status.value);
      if (heartbeat) {
        resetHeartbeat();
        const { message = DEFAULT_PING_MESSAGE } = resolveNestedOptions(heartbeat);
        if (e.data === message) return;
      }
      const jsonData = Object.assign(JSON.parse(e.data), { time: Date.now() });
      if (jsonData.s == 0 && jsonData.d !== null) {
        if (jsonData.d?.extra?.type == 'user_token_expired') {
          data.value = {};
          close();
          createMessage.error(jsonData.d?.content);
          await userStore.logout();
          return;
        }
        data.value = jsonData;
      }
      if (jsonData.s == 1 || jsonData.s == 3) {
        // 登录过程中被踢下线或者token过期 || 用户未登录
        if (jsonData.d?.code == ResultEnum.NO_LOGIN) {
          data.value = {};
          close();
          createMessage.error(jsonData.d?.content);
        } else {
          data.value = jsonData;
        }
      }
    };

    //监听连接关闭事件
    ws.onclose = function (ev) {
      console.log('🚀 ~ file: useWebsocket.ts:61 ~ useWebSocket ~ ev:', ev);
      //监听整个过程中websocket的状态
      console.log('ws连接状态：' + ws.readyState);
      status.value = 'CLOSED';
      wsRef.value = undefined;
    };

    //监听并处理error事件
    ws.onerror = function (error) {
      console.log(error);
    };
  };

  const open = () => {
    console.log('status', status.value);
    if (status.value == 'CLOSED') {
      close();
      _init();
    }
  };

  return {
    data,
    close,
    status,
    open,
    ws: wsRef,
  };
}
