import io from 'socket.io-client';
import PubSub from 'pubsub-js';
import { ref, onMounted, onUnmounted, onBeforeUnmount } from 'vue';
import { clearInterval, clearTimeout, setInterval, setTimeout } from 'worker-timers';

export function useWs() {
  const address: any = import.meta.env.VITE_APP_BASE_API;
  const token: any = localStorage.getItem('token');
  const myInfo: any = localStorage.getItem('userInfo');
  let socket: any = null; //ws实例对象
  let timerManager: any = {}; //计时器管理
  let parameter: any = {}; //参数
  let testTime: number = 0; //默认时长
  let userInfo: any = JSON.parse(myInfo); //用户信息
  let beatTime: number = 10000; //心跳频率
  let loading: any = null; //遮罩层
  let version: string = ''; //ws接口版本v2表示单ws多项目
  let examStateList: any = []; //当前状态码
  let testList: any = []; //区列表
  let wkList: any = []; //工作站列表
  let loadingTime: any = null; //记录等待时间

  socket = io(address + '/midexam', {
    transports: ['websocket', 'polling'],
    query: {
      type: 'train',
      Authorization: 'JWT ' + token,
      sysuuid: 'JWT ' + token
    }
  });

  async function initWs(data: any, callback: any) {
    examStateList = []; //当前状态码
    testList = []; //区列表
    wkList = []; //工作站列表
    loading = ElLoading.service({ text: '正在初始化，请稍候', background: 'rgba(0, 0, 0, 0.8)', customClass: `sports ${data.parameter.project}` });
    parameter = data.parameter;
    testTime = data.testTime;
    version = data.version || '';
    testList = data.parameter.area.split(',');
    examStateList = testList.map((item: any) => {
      let examId = `${parameter.project}_${item}`;
      let obj = {
        examState: 0,
        examId: examId,
        beatNumber: 0,
        wsStatus: 0
      };
      return obj;
    });
    loadingTime = setTimeout(() => {
      //20秒还在0状态就算超时
      let list = examStateList.filter((item: any) => {
        return item.examState == 0;
      });
      //考虑到多开只有一个在线也有效的
      if (list.length == testList.length) {
        clearTimeout(loadingTime);
        for (const item of testList) {
          let examId = `${parameter.project}_${item}`;
          console.log(`【${examId}】前端发送disconnect_request，code：1`)
          callback({ cmd: 'disconnect_request', exam_id: examId, data: { message: 'WS连接超时' } });
        }
      }
    }, 20000);
    socket.on('connect', async (e: any) => {
      callback({ cmd: 'mySid', data: { sid: socket.id.replace('/midexam#', '') } });
      if (testList.length > 1) {
        //单WS多区直接执行
        for (const item of testList) {
          await delay(100); // 延时
          let examId = `${parameter.project}_${item}`;
          if (parameter.taskId) {
            getTaskStarts(examId);
          } else {
            getExamStarts(examId);
          }
          getNetWork(examId, (e: any) => {
            if (!e.status) {
              // console.log(`【${examId}】前端发送disconnect_request，code：2`)
              // callback({ cmd: 'disconnect_request', exam_id: examId, data: { message: '工作站未响应' } });
            }
          });
        }

        //分组延迟执行
        // let num = 10; //每次执行N个
        // let time = 200; //间隔时间毫秒
        // let group = Math.ceil(testList.length / num);
        // for (let i = 0; i < group; i++) {
        //   for (let j = i * group; j < (i + 1) * num; j++) {
        //     setTimeout(() => {
        //       let item = testList[j];
        //       let examId = `${parameter.project}_${item}`;
        //       if (parameter.taskId) {
        //         getTaskStarts(examId);
        //       } else {
        //         getExamStarts(examId);
        //       }
        //       getNetWork(examId, (e: any) => {
        //         if (!e.status) {
        //           callback({ cmd: 'disconnect_request', exam_id: examId, data: { message: '工作站未响应' } });
        //         }
        //       });
        //     }, time * i);
        //   }
        // }
      } else {
        //单WS单区
        let examId = parameter.examId;
        if (parameter.taskId) {
          getTaskStarts(examId);
        } else if (['skiprope', 'heartbeat'].includes(parameter.project)) {
          getDeviceStarts(examId);
        } else {
          getExamStarts(examId);
        }
        getNetWork(examId, (e: any) => {
          if (!e.status) {
            // console.log(`【${examId}】前端发送disconnect_request，code：3`)
            // callback({ cmd: 'disconnect_request', exam_id: examId, data: { message: '工作站未响应' } });
          }
        });
      }
    });

    socket.on('msg2frontend', (e: any) => {
      callback(e);
      if (['init_result', 'set_exam_state', 'disconnect_request'].includes(e.cmd)) {
        //心跳'exam_status'
        console.log(`【接收：${e.cmd}】`, JSON.stringify(e));
      }
      //实时状态
      if (e.cmd === 'exam_status') {
        let index = examStateList.findIndex((item: any) => {
          return item.examId == e.exam_id;
        });
        if (index != -1) {
          examStateList[index].examState = e.data;
          examStateList[index].beatNumber = examStateList[index].beatNumber + 1;
          examStateList[index].wsStatus = e.status;
        }
      }
      //工作站状态
      if (e.cmd === 'init_result') {
        if (e.status == 666) {
          let data = {
            wk_id: e.data.wk_id,
            examId: e.exam_id
          };
          wkList.push(data);
        }
      }
      //测试违规
      if (e.cmd === 'warning_result') {
      }
      //后端播报语音
      if (e.cmd === 'return_audio_msg') {
      }
      //错误提示
      if (e.cmd === 'info_result') {
      }
      //错误提示
      if (e.cmd === 'error_result') {
      }
      //测试中违规提示
      if (e.cmd === 'warning_notify') {
        if ([233].includes(e.status)) {
          let examId = e.exam_id;
          console.log(`【${examId}】前端发送disconnect_request，code：4`)
          callback({ cmd: 'disconnect_request', exam_id: examId, data: { message: e.data.message } });
        }
      }
      //断线状态
      if (e.cmd === 'disconnect_request') {
        if (loadingTime) {
          clearTimeout(loadingTime);
        }
        if (testList.length > 1) {
          //如果全部的WS状态都为213、220就退出
          let list = examStateList.filter((item: any) => {
            return [213, 220, 302].includes(item.wsStatus);
          });
          if (list.length == testList.length) {
            getExit();
          }
        }
        if (testList.length == 1) {
          getExit();
          //let examId = e?.exam_id || '';
          //getExit(examId);
        }
      }
      //状态变更
      if (e.cmd === 'set_exam_state') {
        // getClearExamStateTimer();
        let index = examStateList.findIndex((item: any) => {
          return item.examId == e.exam_id;
        });
        if (index != -1) {
          examStateList[index].examState = e.data;
          examStateList[index].wsStatus = e.status;
          PubSub.publish(`${e.exam_id}_${e.data}`, e);
        }
        if (e.data == 3) {
          //关闭遮罩层
          loading?.close();
          clearTimeout(loadingTime);
        }
      }
      //新建测试后返回信息，获取result_id
      if (e.cmd === 'open_one_test_ack') {
      }
      //人脸识别状态
      if (e.cmd === 'face_check_result') {
      }
      //测试结束结果
      if (e.cmd === 'oneresult') {
      }
      //结果生成完成（视频图片）
      if (e.cmd === 'static_urls_finished') {
      }
      //选择学生或测试结束后返回的数据
      if (e.cmd === 'result_info') {
      }
    });

    socket.on('disconnect', (e: any) => {
      callback(e);
      getExit();
    });
  }

  /**
   * 发送命令
   * @param type发送类型：v2版是单WS多人的项目
   * msgfrom_frontend：测试中命令交互，
   * get_exam_status：心跳，
   * exam_ends：结束测试，
   * fe_reconnect:重连，
   * task_starts：课程开启测试，
   * exam_starts：开启测试，
   * join_exam_room：加入房间，
   * @param data发送数据：
   * msgfrom_frontend发送cmd的参：
   * open_one_test:创建测试将由3转40，
   * start_face_recognition:开始人脸识别将由40转41，
   * stop_face_recognition:停止人脸识别将由41转43，
   * face_confirm_only:人脸确认即将测试，
   * start_one_test:开始测试将由43转42，
   * finish_one_test:正在测试中结束并下一次将由42转6转3，
   * close_one_test:中断任何阶段将由42、43、41、40转3，
   * suspend_face_recognition_channels:工作站识别的短跑，某道识别到了人就停止某道的识别，
   * resume_face_recognition_channels:工作站识别的短跑，重新开启某一道的识别，
   * next_test:，
   * result_info:，
   * @param callback回调函数
   */
  function sendMessage(type: string, data: any, callback?: () => void) {
    if (socket?.connected) {
      callback = callback || function () { };
      //版本2就拼接进去
      if (version == 'v2') {
        type = type + '_' + version;
      }
      if (['task_starts', 'exam_starts', 'msgfrom_frontend', 'exam_ends', 'task_starts_v2', 'exam_starts_v2', 'msgfrom_frontend_v2', 'exam_ends_v2'].includes(type)) {
        //这两个是心跳 'get_exam_status', 'get_exam_status_v2'
        console.log(`【发送：${type}】`, JSON.stringify(data))
      }
      socket.emit(type, JSON.stringify(data), callback);
    }
  }

  /**
   * 课程连接成功
   */
  function getTaskStarts(data?: any) {
    let examId = data ? data : parameter.examId;
    sendMessage(
      'task_starts',
      {
        data: 'start_' + examId,
        class_id: parameter.classes,
        exam_type: parameter.standard,
        task_id: parameter.taskId,
        task_cate: parameter.taskCate,
        gesture: parameter.gesture,
        demo: parameter.demo,
        test_time: testTime
      },
      () => { }
    );
  }

  /**
   * 设备连接成功
   */
  function getDeviceStarts(data?: any) {
    let examId = data ? data : parameter.examId;
    sendMessage(
      'device_starts',
      {
        data: 'start_' + examId,
        class_id: 1,
        exam_type: parameter.standard,
        etime: testTime
      },
      () => { }
    );
  }

  /**
   * 连接成功
   */
  function getExamStarts(data?: any) {
    let examId = data ? data : parameter.examId;
    sendMessage(
      'exam_starts',
      {
        data: 'start_' + examId,
        class_id: parameter.classes,
        exam_type: parameter.standard,
        gesture: parameter.gesture,
        demo: parameter.demo,
        test_time: testTime
      },
      () => { }
    );
  }

  /**
   * 创建测试
   */
  function openOneTest(data?: any) {
    return new Promise((resolve, reject) => {
      let examId = data ? data : parameter.examId;
      let index = examStateList.findIndex((item: any) => {
        return item.examId == examId;
      });
      sendMessage('msgfrom_frontend', {
        data: {
          cmd: 'open_one_test',
          exam_id: examId
        }
      });
      PubSub.subscribe(`${examId}_40`, (eventName: any, res: any) => {
        if (res.data == 40) {
          resolve({ data: examStateList[index].examState });
        }
      });
    });
  }

  /**
   * 开始人脸识别
   */
  function startFace(data?: any) {
    return new Promise((resolve, reject) => {
      let examId = data ? data : parameter.examId;
      let index = examStateList.findIndex((item: any) => {
        return item.examId == examId;
      });
      sendMessage('msgfrom_frontend', {
        data: {
          cmd: 'start_face_recognition',
          exam_id: examId
        }
      });
      PubSub.subscribe(`${examId}_41`, (eventName: any, res: any) => {
        if (res.data == 41) {
          resolve({ data: examStateList[index].examState });
        }
      });
    });
  }

  /**
   * 停止人脸识别
   */
  function stopFace(data?: any) {
    return new Promise((resolve, reject) => {
      let examId = data ? data : parameter.examId;
      let index = examStateList.findIndex((item: any) => {
        return item.examId == examId;
      });
      sendMessage('msgfrom_frontend', {
        data: {
          cmd: 'stop_face_recognition',
          exam_id: examId
        }
      });
      PubSub.subscribe(`${examId}_43`, (eventName: any, res: any) => {
        if (res.data == 43) {
          resolve({ data: examStateList[index].examState });
        }
      });
    });
  }

  /**
   * 确认并提交人脸
   */
  function faceConfirmOnly(data: any, callback?: any) {
    let examId = data.exam_id ? data.exam_id : parameter.examId;
    let myData = null;
    if (Array.isArray(data)) {
      //数组类型
      myData = {
        cmd: 'face_confirm_only',
        data
      };
    } else {
      //对象类型
      myData = {
        cmd: 'face_confirm_only',
        exam_id: examId,
        result_id: data.result_id,
        student_id: data.student_id,
        gender: data.gender
      };
    }
    sendMessage(
      'msgfrom_frontend',
      {
        data: myData
      },
      () => {
        callback();
      }
    );
  }

  /**
   * 开始测试
   */
  function startOneTest(data?: any, callback?: any) {
    let examId = data ? data : parameter.examId;
    sendMessage(
      'msgfrom_frontend',
      {
        data: {
          cmd: 'start_one_test',
          exam_id: examId
        }
      },
      () => {
        callback();
      }
    );
  }

  /**
   * 停止测试
   */
  function finishOneTest(data?: any) {
    return new Promise((resolve, reject) => {
      let examId = data ? data : parameter.examId;
      let index = examStateList.findIndex((item: any) => {
        return item.examId == examId;
      });
      sendMessage('msgfrom_frontend', {
        data: {
          cmd: 'finish_one_test',
          exam_id: examId
        }
      });
      PubSub.subscribe(`${examId}_3`, (eventName: any, res: any) => {
        if (res.data == 3) {
          resolve({ data: examStateList[index].examState });
        }
      });
    });
  }

  /**
   * 关闭测试
   */
  function closeOneTest(data?: any) {
    return new Promise((resolve, reject) => {
      let examId = data ? data : parameter.examId;
      let index = examStateList.findIndex((item: any) => {
        return item.examId == examId;
      });
      sendMessage('msgfrom_frontend', {
        data: {
          cmd: 'close_one_test',
          exam_id: examId
        }
      });
      PubSub.subscribe(`${examId}_3`, (eventName: any, res: any) => {
        if (res.data == 3) {
          resolve({ data: examStateList[index].examState });
        }
      });
    });
  }

  /**
   * 某道识别到了人就停止某道的识别
   */
  function suspendFaceRecognitionChannels(data: any) {
    let track = data;
    sendMessage('msgfrom_frontend', {
      data: {
        cmd: 'suspend_face_recognition_channels',
        track: track
      }
    });
  }

  /**
   * 某道重新开始识别
   */
  function resumeFaceRecognitionChannels(data: any) {
    let track = data;
    sendMessage('msgfrom_frontend', {
      data: {
        cmd: 'resume_face_recognition_channels',
        track: track
      }
    });
  }

  /**
   * 心跳
   */
  function getNetWork(data: any, callback?: any) {
    timerManager[data] = setInterval(() => {
      let obj = wkList.find((item: any) => {
        return item.examId == data;
      });
      if (obj == undefined) {
        return false;
      }
      let wk_id = obj.wk_id;
      let examId = data ? data : parameter.examId;
      sendMessage(
        'get_exam_status',
        {
          exam_id: examId,
          wk_id: wk_id,
          school_id: userInfo.school_id || null
        },
        () => {
          //如果心跳停止了就退出去
          let index = examStateList.findIndex((item: any) => {
            return item.examId == examId;
          });
          if (index == -1) {
            return false;
          }
          let beforBeatNumber = JSON.parse(JSON.stringify(examStateList[index].beatNumber));
          setTimeout(() => {
            //5秒后验证是否有变
            if (beforBeatNumber == examStateList[index].beatNumber) {
              //异常
              callback({ status: false });
            } else {
              //正常
              callback({ status: true });
            }
          }, 5000);
        }
      );
    }, beatTime);
  }

  /**
   * 关闭项目
   */
  function examEnds() {
    getExit();
  }

  /**
   * 退出
   */
  function getExit() {
    //关闭遮罩层
    loading?.close();
    //清除计时器
    getClearTimer();
    //取消订阅
    PubSub.clearAllSubscriptions();
    //通知工作站关闭
    if (testList.length > 1) {
      //单WS多区
      examStateList.forEach((item: any) => {
        let examId = item.examId;
        sendMessage('exam_ends', {
          data: 'end_' + examId,
          class_id: parameter.classes
        });
      });
    } else {
      //单WS单区
      let examId = parameter.examId;
      sendMessage('exam_ends', {
        data: 'end_' + examId,
        class_id: parameter.classes
      });
    }
    //如果正在连接就关闭
    if (socket?.connected) {
      socket?.close();
    }
  }

  /**
   * 清空定时任务
   */
  function getClearTimer() {
    for (let key in timerManager) {
      if (timerManager.hasOwnProperty(key)) {
        clearInterval(timerManager[key]);
        timerManager[key] = null;
      }
    }
  }

  /**
   * 控制延时
   */
  function delay(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  onBeforeUnmount(() => {
    getClearTimer();
    if (socket) {
      socket.close();
      socket = null;
    }
  });

  return {
    initWs,
    sendMessage,
    openOneTest,
    startFace,
    stopFace,
    faceConfirmOnly,
    startOneTest,
    finishOneTest,
    closeOneTest,
    suspendFaceRecognitionChannels,
    resumeFaceRecognitionChannels,
    getNetWork,
    examEnds
  };
}
