<script setup lang="ts">
/*
 * 组件名: spatialOrientationAbility
 * 组件用途: 空间定向训练
 * 创建日期: 2024/8/16
 * 编写者: JutarryWu
 */
import { shuffle } from 'lodash-es'
import { Decimal } from 'decimal.js'
import { generateRandomNumbers } from '@/utils'
import Url_forest from '@/assets/images/task/spatialOrientationAbility/forest.png'
import Url_hospital from '@/assets/images/task/spatialOrientationAbility/hospital.png'
import Url_lakes from '@/assets/images/task/spatialOrientationAbility/lakes.png'
import Url_massif from '@/assets/images/task/spatialOrientationAbility/massif.png'
import Url_cat from '@/assets/images/task/spatialOrientationAbility/cat.png'
import Url_flower from '@/assets/images/task/spatialOrientationAbility/flower.png'
import Url_car from '@/assets/images/task/spatialOrientationAbility/car.png'
import Url_trafficLight from '@/assets/images/task/spatialOrientationAbility/trafficLight.png'
import Url_stop from '@/assets/images/task/spatialOrientationAbility/stop.png'
import Url_house from '@/assets/images/task/spatialOrientationAbility/house.png'

interface IData {
  level?: number
  onceStartTime?: string
  onceEndTime?: string
  reactionTime?: number
  xAxis?: string | number
  yAxis?: string | number
  id?: number
  text?: string
  name?: string
  value?: string
  imgUrl?: string
  angle?: string
}

const subjectInfo = ref({
  name: '空间定向训练',
})

const showCountDown = ref(false) // 显示倒计时
const showCountDownBottom = ref(false) // 显示底部倒计时
const showSubmit = ref(false) // 显示画布
const isSubmit = ref(false) // 是否提交进程中

const levelNum = [3, 5, 7] // 正式测试：3个难度等级需要呈现的刺激目标数
const tryCount = 3 // 正式测试：每个难度等级需要进行的试次数
const currentIndex = ref(0) // 当前试次索引值：练习模式2次最大为1， 正式测试45次
const itemAngle = ref(0) // 选项物品实际角度
const roundSliderVal = ref(0) // 圆形滑杆产生的值（即：用户操作实际角度）
const offsetAngle = ref(0) // 角度偏差值(用户绘制时产生的实际偏差值)

const showDataArr = ref<IData[][]>([]) // 伪随机数组
let arrDataDemo: IData[] = [
  { id: 0, text: '森林', name: '森林', value: 'forest', imgUrl: Url_forest, angle: '', xAxis: '', yAxis: '' },
  { id: 1, text: '医院', name: '医院', value: 'hospital', imgUrl: Url_hospital, angle: '', xAxis: '', yAxis: '' },
  { id: 2, text: '湖泊', name: '湖泊', value: 'lakes', imgUrl: Url_lakes, angle: '', xAxis: '', yAxis: '' },
  { id: 3, text: '山', name: '山', value: 'massif', imgUrl: Url_massif, angle: '', xAxis: '', yAxis: '' },
  { id: 4, text: '猫', name: '猫', value: 'cat', imgUrl: Url_cat, angle: '', xAxis: '', yAxis: '' },
  { id: 5, text: '花', name: '花', value: 'flower', imgUrl: Url_flower, angle: '', xAxis: '', yAxis: '' },
  { id: 6, text: '车', name: '车', value: 'car', imgUrl: Url_car, angle: '', xAxis: '', yAxis: '' },
  {
    id: 7,
    text: '红绿灯',
    name: '红绿灯',
    value: 'trafficLight',
    imgUrl: Url_trafficLight,
    angle: '',
    xAxis: '',
    yAxis: '',
  },
  { id: 8, text: '停止牌', name: '停止牌', value: 'soldier', imgUrl: Url_stop, angle: '', xAxis: '', yAxis: '' },
  { id: 9, text: '房子', name: '房子', value: 'house', imgUrl: Url_house, angle: '', xAxis: '', yAxis: '' },
]
const firstObj = ref<IData>()
const centerCoordinate = ref<IData>()
const secondObj = ref<IData>()
const topCoordinate = ref<IData>()
const thirdObj = ref<IData>()
const thirdCoordinate = ref<IData>()
const resultDataArr = ref([]) // 存放结果数组

/**
 * 生成不重叠随机点
 * @param centerX
 * @param centerY
 * @param radius
 * @param existingPoints
 */
function generateRandomPoint(centerX: number, centerY: number, radius: number, existingPoints: Record<string, any>[]) {
  const angle = Math.random() * 2 * Math.PI
  const distance = Math.sqrt(Math.random()) * radius // 确保点更均匀地分布在圆内
  const xAxis = centerX + distance * Math.cos(angle)
  const yAxis = centerY + distance * Math.sin(angle)

  // 检查是否与现有点重叠
  for (const point of existingPoints) {
    const dx = xAxis - point.xAxis
    const dy = yAxis - point.yAxis
    if (Math.sqrt(dx * dx + dy * dy) < radius / 3) {
      // 阈值设为半径的1/4
      return generateRandomPoint(centerX, centerY, radius, existingPoints) // 递归调用直到找到合适的点
    }
  }

  return { xAxis, yAxis }
}

function generateNonOverlappingPoints(centerX: number, centerY: number, radius: number, num: number) {
  const points = [{ xAxis: centerX, yAxis: centerY }] // 中心点
  for (let i = 0; i < num; i++) {
    const newPoint = generateRandomPoint(centerX, centerY, radius, points)
    points.push(newPoint)
  }
  return points.map((item) => {
    return {
      xAxis: item.xAxis + 16,
      yAxis: item.yAxis + 16,
    }
  })
}

function createThreeObj() {
  const arr = generateRandomNumbers(3, showDataArr.value[currentIndex.value].length).map((item: number) => item - 1)

  firstObj.value = showDataArr.value[currentIndex.value][arr[0]]
  centerCoordinate.value = showDataArr.value[currentIndex.value][arr[0]]

  secondObj.value = showDataArr.value[currentIndex.value][arr[1]]
  topCoordinate.value = showDataArr.value[currentIndex.value][arr[1]]

  thirdObj.value = showDataArr.value[currentIndex.value][arr[2]]
  thirdCoordinate.value = showDataArr.value[currentIndex.value][arr[2]]

  showCountDownBottom.value = false
  submitQuestion()
}

function submitQuestion() {
  // 计算选项角度
  const topCenterX = Number(topCoordinate.value.xAxis) - Number(centerCoordinate.value.xAxis)
  const topCenterY = Number(topCoordinate.value.yAxis) - Number(centerCoordinate.value.yAxis)
  const thirdCenterX = Number(thirdCoordinate.value.xAxis) - Number(centerCoordinate.value.xAxis)
  const thirdCenterY = Number(thirdCoordinate.value.yAxis) - Number(centerCoordinate.value.yAxis)
  getAngle({ x: topCenterX, y: topCenterY }, { x: thirdCenterX, y: thirdCenterY })

  // 显示画布
  showSubmit.value = true
}

function getAngle({ x: x1, y: y1 }, { x: x2, y: y2 }) {
  const dot = x1 * x2 + y1 * y2
  const det = x1 * y2 - y1 * x2
  // const angle = Math.atan2(det, dot) / Math.PI * 180;
  const angle = Math.atan2(det, dot) * (180 / Math.PI)
  // return (angle + 360) % 360;
  itemAngle.value = Math.abs(angle)
  // console.log('---------------------------------------------------------------')
  // console.log('物品实际角度值: ', itemAngle.value)
  // console.log('---------------------------------------------------------------')
}

// 以下生成随机位置显示图例方法
function initImgData(level: number, num: number) {
  // 随机生成6个物品的位置
  const items = generateNonOverlappingPoints(165, 176, 165, num - 1)
  arrDataDemo = shuffle(arrDataDemo)
  const tempItems: IData[] = arrDataDemo.slice(0, num)
  const extraInfo = {
    level: levelNum[level],
    onceStartTime: '',
    onceEndTime: '',
    reactionTime: 0,
  }
  items.forEach((item, index) => {
    tempItems[index] = { ...tempItems[index], ...item, ...extraInfo }
  })
  return tempItems
}

function initImgDataList() {
  for (let i = 0; i < levelNum.length; i++) {
    let tempTryCount = tryCount
    while (tempTryCount > 0) {
      const tempData: IData[] = initImgData(i, levelNum[i])
      showDataArr.value.push(tempData)
      tempTryCount--
    }
  }
  showDataArr.value = shuffle(showDataArr.value)
}

function angleDiffVal(val: number) {
  roundSliderVal.value = val
}

function // 提交数据
submitAngle() {
  // showDataArr.value[currentIndex.value].onceEndTime = Date.now()
  isSubmit.value = true
  offsetAngle.value = Number((Math.abs(itemAngle.value - roundSliderVal.value)).toFixed(2))
  // console.log('---------------------------------------------------------------')
  // console.log('物品实际角度值: ', itemAngle)
  // console.log('用户操作角度值: ', roundSliderVal)
  // console.log('用户操作逻辑角度值: ', roundSliderVal)
  // console.log('角度偏差值: ', offsetAngle)
  // console.log('---------------------------------------------------------------')
  resultDataArr.value.push({
    // level: showDataArr.value[currentIndex.value][0].level,
    // onceStartTime: dayjs(new Date(showDataArr.value[currentIndex.value].onceStartTime)).format('YY-mm-dd HH:MM:SS'),
    // onceEndTime: dayjs(new Date(showDataArr.value[currentIndex.value].onceEndTime)).format('YY-mm-dd HH:MM:SS'),
    // reactionTime: (showDataArr.value[currentIndex.value].onceEndTime - showDataArr.value[currentIndex.value].onceStartTime).toFixed(2),
    itemAngle: itemAngle.value.toFixed(2), // 物品实际角度值
    rotationAngle: Math.abs(roundSliderVal.value).toFixed(2), // 用户操作逻辑角度值
    offsetAngle: offsetAngle.value, // 角度偏差值
    CenterName: centerCoordinate.value.name, // 中心点物体
    BeseName: topCoordinate.value.name, // 顶点物体
    TargetName: thirdCoordinate.value.name, // 目标物体
    randomArr: dealArrDataPoint(showDataArr.value[currentIndex.value], centerCoordinate.value), // 物品随机坐标位置
  })
  currentIndex.value++
  // curPercentage.value = Number(roundToFixed((currentIndex.value / showDataArr.value.length), 2))
  if (currentIndex.value < showDataArr.value.length) {
    resetGame()
  }
  else {
    // taskEndTime.value = Date.now()
    // console.log(`本次 空间定向任务共计耗时：${taskEndTime.value - taskStartTime.value}ms`, resultDataArr.value)
    // $http.post(
    //   `/cognize/SpatialOrientation`,
    //   {
    //     userId: userId,
    //     userResponseRecords: resultDataArr,
    //     testPlanId: $route.query.testPlanId || '',
    //     taskStartTime: dateFormat('YY-mm-dd HH:MM:SS', new Date(taskStartTime)),
    //     taskEndTime: dateFormat('YY-mm-dd HH:MM:SS', new Date(taskEndTime)),
    //   },
    //   (res) => {
    //     console.log('res: ', res)
    //     if (res && res.code === '200') {
    //       // 跳转新测试结果页面
    //       goTestResult(res.data)
    //     }
    //     else {
    //       $toast.fail(res?.msg)
    //     }
    //
    //     setTimeout(() => {
    //       isSubmit = false
    //     }, 500)
    //   },
    // )
  }
}

/**
 * 以centerPoint为中心坐标(0, 0)， 修改其他图标的坐标值
 * @param arrData
 * @param centerPoint
 */
function dealArrDataPoint(arrData: IData[], centerPoint: IData) {
  const xAxisOffset = new Decimal(centerPoint.xAxis)
  const yAxisOffset = new Decimal(centerPoint.yAxis)
  return arrData.map((item) => {
    const xAxis = new Decimal(item.xAxis)
    const yAxis = new Decimal(item.yAxis)
    item.xAxis = xAxis.minus(xAxisOffset).toNumber()
    item.yAxis = yAxis.minus(yAxisOffset).toNumber()
    return item
  })
}

function resetGame() {
  showCountDown.value = false
  isSubmit.value = false
  offsetAngle.value = 0
  itemAngle.value = 0
  roundSliderVal.value = 0
  firstObj.value = null
  secondObj.value = null
  thirdObj.value = null
  centerCoordinate.value = null
  // 调用任务方法开始任务
  // 随机点位已生成，展示在画布上
  showSubmit.value = false
  showCountDownBottom.value = true
}

function exec() {
  showCountDown.value = false
  showCountDownBottom.value = true
}

onMounted(() => {
  showCountDown.value = true
  initImgDataList()
})
</script>

<template>
  <section class="app-container">
    <van-nav-bar class="self-nav-bar" :title="subjectInfo.name" />
    <count-down v-if="showCountDown" :time="5" @end-count-down="exec" />
    <div v-if="!showCountDown && !showSubmit" class="opt-bg-area absolute-center h-[370px] w-[350px] rounded-[8px] bg-[#FFFFFF8B] shadow-lg">
      <div
        v-for="(arr, index) in showDataArr[currentIndex]"
        :key="index"
        class="item flex-column absolute translate-[-50%] text-[16px] text-black"
        :style="{ top: `${arr.yAxis}px`, left: `${arr.xAxis}px` }"
      >
        <img :src="arr.imgUrl" alt="" class="h-[28px] w-[28px]">
        <span>{{ arr.name }}</span>
      </div>
    </div>

    <div class="absolute bottom-[12px] right-[8px] h-[118px] w-[108px]">
      <count-down v-if="showCountDownBottom" :time="10" text="" color="rgba(194, 194, 194, 0.6)" :size="74" @end-count-down="createThreeObj" />
    </div>

    <template v-if="showSubmit">
      <div class="ml-[4%] mt-[10px] w-[92%] text-center text-[15px] text-[#3A3A3A]">
        在刚刚呈现的图片中，请您想象当您站在
        <span class="text-[18px] text-[#F87171] font-600">{{ firstObj.name }}</span>
        的位置同时面向
        <span class="text-[18px] text-[#F87171] font-600">{{ secondObj.name }}</span>
        时，用红色线条标出
        <span class="text-[18px] text-[#F87171] font-600">{{ thirdObj.name }}</span>
        所在的方向。
      </div>

      <div class="absolute-center h-[370px] w-[350px] rounded-[8px] bg-[#FFFFFF8B] shadow-lg">
        <div class="opt-bg-circle absolute-center h-[286px] w-[284px]">
          <RoundSlider
            :center-name="firstObj.name"
            :top-name="secondObj.name"
            :move-name="thirdObj.name"
            @cur-value="angleDiffVal"
          />
        </div>
      </div>
      <van-button
        type="primary"
        color="#00AABD"
        class="bottom-block-btn"
        :disabled="isSubmit"
        @click="submitAngle()"
      >
        确定
      </van-button>
    </template>
  </section>
</template>

<style scoped lang="less">
.app-container {
  background-image: url('@/assets/images/bg-soa.png');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center; /* 可选，让图片居中对齐 */

  .opt-bg-area {
    background-image: url('@/assets/images/task/spatialOrientationAbility/bg_shape.png');
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center; /* 可选，让图片居中对齐 */

    .opt-bg-circle {
      background-image: url('@/assets/images/task/spatialOrientationAbility/bg_circle.png');
      background-size: cover;
      background-repeat: no-repeat;
      background-position: center; /* 可选，让图片居中对齐 */
    }
  }
}
</style>
