import Actions from '@/types/Store/Actions';
import Taro, { useReducer, useEffect } from '@tarojs/taro';
import { str2ab, ab2str } from '@/utils/arrayBuffer';

type StoreState = {
  socketState: boolean;
  socketTask: Taro.SocketTask | null;
};
const StopCode = 1000;
let reConnectting: boolean = false;
let timer: NodeJS.Timeout | null = null;

const initState = {
  socketState: false,
  socketTask: null,
};
const reducer = (state: StoreState, action: Actions): StoreState => {
  switch (action.type) {
    case 'GET_SOCKET_TASK':
      return { ...state, socketTask: action.payload };
    case 'SOCKET_STATE_CHANGE':
      return { ...state, socketState: action.payload };
    default:
      return state;
  }
};

const useDeviceWS = ({
  url,
  getSocketData,
}: {
  url: string;
  getSocketData: (msg: string) => void;
}) => {
  const [state, dispatch] = useReducer(reducer, initState);

  const connectDeviceSocket = () => {
    console.log('connectDeviceSocket: ', url);

    Taro.connectSocket({ url: url }).then(task => {
      dispatch({ type: 'GET_SOCKET_TASK', payload: task });
      task.onOpen(() => {
        console.log('onOpen');
        if (reConnectting) {
          // reConnectDeviceSocket(true);
          timer && clearTimeout(timer);
          timer = null;
          reConnectting = false;
        }
        task.send({ data: str2ab('{}') });
        dispatch({ type: 'SOCKET_STATE_CHANGE', payload: true });
        // this.sendDeviceCode();
      });
      task.onMessage(res => {
        const msg: string = ab2str(res.data);
        console.log('socket onMessage: ', msg);
        if (msg === '[0]') {
          console.log('结束蓝牙以及socket: ', msg);
          closeDeviceSocket();
        } else if (msg === '[]') {
        } else {
          if (msg.length > 100) {
            getSocketData('[]');
          } else if (msg.length > 20) {
            for (let index = 0; index <= Math.floor(msg.length / 20); index++) {
              let str = msg.substring(index * 20, (index + 1) * 20);
              getSocketData(str);
            }
          } else {
            if (msg) {
              getSocketData(msg);
            }
          }
        }
      });
      task.onClose(e => {
        console.log('socked关闭', e, reConnectting, timer);

        dispatch({ type: 'SOCKET_STATE_CHANGE', payload: false });
        dispatch({ type: 'GET_SOCKET_TASK', payload: null });
        if (e.code === StopCode) {
          console.log('正确结束socket连接');
        } else {
          console.log('开始重连socket');
          reConnectDeviceSocket();
        }
      });
    });
  };

  const closeDeviceSocket = () => {
    const { socketTask } = state;
    console.log('in close', socketTask, timer);
    if (socketTask) {
      socketTask.close({
        code: StopCode,
        complete: () => {
          dispatch({ type: 'SOCKET_STATE_CHANGE', payload: false });
          dispatch({ type: 'GET_SOCKET_TASK', payload: null });
        },
      });
    }
    if (timer) {
      clearTimeout(timer);
    }
  };

  const reConnectDeviceSocket = () => {
    console.log(reConnectting, timer);
    if (reConnectting) {
      connectDeviceSocket();
    } else if (timer) {
      clearTimeout(timer);
      reConnectting = false;
      timer = null;
      console.log('请保证网络正常');
      Taro.showModal({
        title: '警告',
        content: '请保持网络畅通正常',
      });
    } else {
      timer = setTimeout(() => {
        reConnectting = false;
      }, 10000);
      reConnectting = true;
      console.log(reConnectting, timer);
      connectDeviceSocket();
    }
  };

  const sendMessageToServer = (
    msg: string,
    successHandle: Taro.SocketTask.send.ParamPropSuccess,
    failHandle: Taro.SocketTask.send.ParamPropFail,
  ) => {
    const { socketTask } = state;
    socketTask &&
      socketTask.send({
        data: str2ab(msg),
        success: successHandle,
        fail: failHandle,
      });
  };

  // useEffect(() => {
  //   console.log(deviceCode);

  //   if (deviceCode) {
  //     connectDeviceSocket(url);
  //   }
  //   return closeDeviceSocket;
  // }, [url, deviceCode]);

  return { state, sendMessageToServer, connectDeviceSocket };
};

export default useDeviceWS;
