<template>
  <van-dialog
    class="BaseApp-dialog BaseApp-dialog--large FaceDialog-dialog"
    v-model:show="cmptVisible"
    :showCancelButton="false"
    :showConfirmButton="false"
    :title="oprTypeName">
    <!-- 头部 -->
    <div slot="title" class="BaseApp-dialog__header">
      <el-button
        v-if="deviceList.length > 1"
        class="header__switch-btn"
        type="text"
        @click="choseDevice">
        切换摄像头-[{{ camerahooseIndex + 1 }}]
      </el-button>
    </div>
    <!-- 主体 -->
    <div class="BaseApp-dialog__main">
      <div class="face-login-box">
        <div class="face-box">
          <video
            id="facevideo"
            autoplay
            muted
            style="width: 100%; height: 100%; border-radius: 50%; object-fit: cover"></video>
          <br />
          <canvas
            id="facecanvasF"
            ref="canvasface"
            width="600"
            height="600"
            style="display: none; position: absolute; top: 0"></canvas>
        </div>
        <!-- <p>人脸识别登录</p> -->
        <div class="tip">请保持您的正脸在取景框内...</div>
        <div @click="cancel" class="face-cancel-btn">取消</div>
      </div>
    </div>
  </van-dialog>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
import { getDeviceInfo } from '@/api/user';
import { useLogin, useIdLogin } from '@/api/login.js';
import { userFaceLogin, bindFaceApi } from '@/api/face.api';
import { doubleUserLogin } from '@/utils/login.js';
import { notify } from '@/utils/message.js';

const props = defineProps({
  oprType: {
    type: String,
    default: 'FACE_SET',
    validator: (value) => ['FACE_LOGIN', 'FACE_SET'].includes(value)
  },
  faceBindId: {
    type: String,
    default: ''
  }
});

const emit = defineEmits(['submit', 'cancel', 'error']);

const loading = ref(false);
const cmptVisible = ref(true);
const oprTypeName = ref('');
const video = ref('');
const canvasface = ref('');
const canvasfaceCtx = ref('');
const timeout = ref('');
const timerInter = ref('');
const status = ref(true);
const stopeVideo = ref('');
const camerahooseIndex = ref(0);
const deviceList = ref([]);
const verify_num = ref(1);

const init = () => {
  if (props.oprType === 'FACE_LOGIN') {
    oprTypeName.value = '人脸登录';
  } else if (props.oprType === 'FACE_SET') {
    oprTypeName.value = `人脸录入`;
  }

  loadDeviceInfo();

  setTimeout(() => {
    initCamera(); // 初始化摄像头
  }, 100);
};

const loadDeviceInfo = () => {
  getDeviceInfo().then((res) => {
    console.log('获取设备信息', res);
    if (res.status) {
      verify_num.value = res.data.data.need_two_face;
    }
  });
};

const initCamera = async () => {
  status.value = true;
  await nextTick(async () => {
    video.value = document.getElementById('facevideo');
    canvasface.value = document.getElementById('facecanvasF');
    canvasfaceCtx.value = canvasface.value.getContext('2d');

    await navigator.mediaDevices.enumerateDevices().then((device) => {
      console.log('输出所有的设备编号', device);
      device.forEach((item) => {
        if (item.kind == 'videoinput') {
          deviceList.value.push({
            label: item.label,
            deviceId: item.deviceId
          });
        }
      });
      console.log('获取到了所有的摄像头设备', deviceList.value);
    });

    camerahooseIndex.value = 0;
    if (localStorage.getItem('FaceDialog_camerahooseIndex')) {
      camerahooseIndex.value = Number.parseInt(localStorage.getItem('FaceDialog_camerahooseIndex'));
    }
    console.log('摄像头选取位置', camerahooseIndex.value, deviceList.value);

    navigator.mediaDevices
      .getUserMedia({
        video: { deviceId: deviceList.value[camerahooseIndex.value].deviceId },
        audio: false
      })
      .then((stream) => {
        video.value.srcObject = stream;
        stopeVideo.value = stream.getTracks()[0];
      });

    video.value.addEventListener('play', () => {
      console.log('摄像头play');
      timerInter.value = setInterval(async () => {
        if (status.value) {
          timeout.value = setTimeout(() => {
            getPhotoLocal();
          }, 1500);
          status.value = false;
        }
      });
    });
  });
};

const choseDevice = () => {
  clearTimeout(timeout.value);
  clearInterval(timerInter.value);
  camerahooseIndex.value++;
  if (camerahooseIndex.value >= deviceList.value.length) {
    camerahooseIndex.value = 0;
  }
  localStorage.setItem('FaceDialog_camerahooseIndex', camerahooseIndex.value);

  navigator.mediaDevices
    .getUserMedia({
      video: { deviceId: deviceList.value[camerahooseIndex.value].deviceId },
      audio: false
    })
    .then((stream) => {
      video.value.srcObject = stream;
      stopeVideo.value = stream.getTracks()[0];
    });
};

const getPhotoLocal = () => {
  canvasfaceCtx.value.clearRect(0, 0, canvasface.value.width, canvasface.value.height);
  canvasfaceCtx.value.drawImage(video.value, 0, 0, 400, 400);
  let imgUrl = saveAsPNG(canvasface.value);
  let newImg = imgUrl.split('base64,')[1];

  if (props.oprType == 'FACE_LOGIN') {
    loginByFace(newImg);
  } else {
    bindByFace(newImg);
  }
};

const saveAsPNG = (c) => {
  return c.toDataURL('image/jpeg', 0.8);
};

const fnClose = () => {
  if (canvasface) {
    canvasfaceCtx.value.clearRect(0, 0, canvasface.value.width, canvasface.value.height);
    video.value.pause();
    clearTimeout(timeout.value);
    clearInterval(timerInter.value);
    stopeVideo.value.stop();
  }
};

const bindByFace = async (imgBase64) => {
  try {
    console.log(props.faceBindId, 'ooooooo');
    const res = await bindFaceApi({ raw: imgBase64 }, props.faceBindId);
    console.log(res, 'ooooooo');
    let data = res.data;
    if (data.code == 200) {
      fnClose();
      notify('人脸绑定成功', 'success ');
      emit('submit');
    } else {
      emit('error', data.desc);
      status.value = true;
    }
  } catch (error) {
    status.value = true;
    throw new Error(error);
  }
};

const loginByFace = async (imgBase64) => {
  try {
    const res = await userFaceLogin({ raw: imgBase64 });
    let data = res.data;
    if (data.code == 200) {
      let id = data.data.user_id;
      let res2 = await useIdLogin({ id });
      let status2 = res2.data.status;
      if (status2 || res2.data.code == 200) {
        let { user_id, user_name } = res2.data.data;
        if (verify_num.value != 2) {
          emit('submit', res2.data.data);
          fnClose();
          return;
        }
        let isDouble = doubleUserLogin(res2.data.data);
        if (isDouble) {
          emit('submit', res2.data.data);
          fnClose();
          return;
        } else {
          status.value = true;
        }
      } else {
        emit('error', '人脸认证失败');
        status.value = true;
      }
    } else {
      emit('error', data.desc);
      status.value = true;
    }
  } catch (error) {
    status.value = true;
    throw new Error(error);
  }
};

const cancel = () => {
  fnClose();
  emit('cancel');
};

onMounted(() => {
  init();
});

onBeforeUnmount(() => {
  fnClose();
});
</script>

<style lang="less" scoped>
.FaceDialog-dialog {
  height: 650px !important;
  .BaseApp-dialog__header {
    display: flex;
    flex-direction: row;
    justify-content: center;
    margin: 15px 0;
    .header__switch-btn {
      font-size: 20px;
    }
  }
  .BaseApp-dialog__main {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  .face-login-box {
    width: 350px;
    height: 350px;
    background: #ffffff;
    border-radius: 4px 4px 4px 4px;
    box-sizing: border-box;
    p {
      font-family: Source Han Sans CN, Source Han Sans CN;
      font-size: 32px;
      color: #ffffff;
    }

    .face-box {
      margin: 0 auto;
      width: 350px;
      height: 350px;
      box-shadow: 0px 4px 8px 1px rgba(97, 101, 188, 0.29);
      border-radius: 50%;
    }
    .tip {
      margin: 25px auto;
      font-family: Source Han Sans CN, Source Han Sans CN;
      font-size: 20px;
      color: #525964;
      text-align: center;
    }
  }
  .face-cancel-btn {
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    width: 160px;
    height: 60px;
    margin: 15px auto;
    background: linear-gradient(180deg, #ffffff 0%, #e5e5e5 100%);
    box-shadow: 0px 3px 6px 1px rgba(0, 0, 0, 0.2);
    border-radius: 8px 8px 8px 8px;
    border: 1px solid #e5e5e5;
    font-size: 21px;
    color: #e24a4a;
  }
}
</style>
