<!--
 * 【界面概述】
 * 展示DispersedItemWidget控件的用法
 *
 * 【控件介绍】
 * DispersedItemWidget:
 *    props:
 *      data {Array} (必传) 用于设置离散型焦点管理的数组对象
        单个对象格式为:{
                width: {int} (必传) 当前item的宽度
                height: {int} (必传) 当前item的高度
                top: {int} (必传) 当前item的top值
                left {int} (必传) 当前item的left值
                SpecIndex {Object} (可选) 指定当前item的某个方向键跳转到目标index 
                                      对应方向键，属性为: up,down,left,right   
               }
 *      name {string} (必传) 用于设置焦点的名称
 *      initFocusId {int} (可选) 初始聚焦Index，默认为0
 *      onEdge (Function) (可选) 当前item在某个方向上无法移动时触发
  slots:
    renderItem: 该slot用于描画每个单元格
 * 【技巧说明】
 * Q: 插槽props如何使用？
 * A: data: 当前item的数据
 *    query: 获取一些额外信息的对象
                { 
                  id: {int} item的id,
                  index: {int} item的index
                }
 *    onAction: 单元格内控件需要通过onAction.register方法向MetroWidget注册 item 的回调，回调函数有
                onFocus， onBlur， onClick,
 *
 * Q: 单元格的普通状态，焦点状态，失焦状态如何渲染？
 * A: 在单元的空间中通过往onAction注册的onFocus，onBlur控制显示
 *
 * Q: 焦点怎么移出控件？
 * A: 当焦点移动到控件边缘时，会调用onEdge回调。在回调中通过参数传递的值来决定焦点转移的行为
 * 
-->

<template>
  <jsv-focus-block
    ref="focusNode"
    :name="props.name"
    :onAction="{
      onFocus: focusBlockOnFocus,
      onBlur: focusBlockOnBlur,
      onKeyDown: focusBlockOnKeyDown,
    }"
  >
    <div
      v-for="(item, index) in innerData"
      :key="'_' + item.index"
      :ref="item.divRef"
      :style="{
        left: item.left,
        top: item.top,
        width: item.width,
        height: item.height,
      }"
    >
      <div :key="`${props.name}_${index}`" :id="`${props.name}_${index}`">
        <slot
          name="renderItem"
          :data="item.customerData"
          :onAction="item.registerObj"
          :query="item.query"
        ></slot>
      </div>
    </div>
  </jsv-focus-block>
</template>

<script setup>
import { MyRenderItem } from "./MyRenderItem";
import { nextTick, shallowRef } from "vue";
let focusNode = shallowRef(null);
let callFocusAfterUpdate = false;
let focusId = 0;
let preEdgeRect = null;
let id = 0;
let index = 0;
let innerData = [];
let preFocusId = -1;
let isFocus = false;
let onKeyDownLock = false;
const props = defineProps({
  data: {
    type: Array,
    require: true,
  },
  initFocusId: {
    type: Number,
  },
  onEdge: {
    type: Function,
  },
  SpecIndex: {
    type: Object,
  },
  name: {
    type: String,
    require: true,
  },
});

const onItemFocus = (focusIndex) => {
  innerData[focusIndex].customerCallbackMap.onFocus();
  return innerData[focusIndex];
};

const onItemBlur = (blurIndex) => {
  innerData[blurIndex].customerCallbackMap.onBlur();
  return innerData[blurIndex];
};
const getItemByIndex = (index) => {
  return innerData[index];
};
const _getPosition = (index) => {
  let templateInfo = getItemByIndex(index);
  return {
    left: templateInfo.customerData.left,
    top: templateInfo.customerData.top,
    width: templateInfo.customerData.width,
    height: templateInfo.customerData.height,
  };
};
const draw = (customerData) => {
  const item = new MyRenderItem(
    customerData,
    () => {
      if (callFocusAfterUpdate && item.id === focusId) {
        nextTick(() => {
          onItemFocus(item, preEdgeRect);
        });
        callFocusAfterUpdate = false;
      }
    },
    //query object
    {
      id: id++,
      index: index++,
      position: _getPosition,
    }
  );
  innerData.push(item);
};

const onItemClick = (focusIndex) => {
  innerData[focusIndex].customerCallbackMap.onClick();
};

//算角度
const getAngleRange = (direction) => {
  switch (direction) {
    case "up":
      return [(5 * Math.PI) / 4, (7 * Math.PI) / 4];
    case "left":
      return [(3 * Math.PI) / 4, (5 * Math.PI) / 4];
    case "down":
      return [Math.PI / 4, (3 * Math.PI) / 4];
    case "right":
      return [(7 * Math.PI) / 4, Math.PI / 4];
    default:
      console.log("direction无效值！");
  }
};

const isAngleInRange = (angle, range) => {
  const [start, end] = range;
  if (start < end) {
    return angle >= start && angle <= end;
  } else {
    return angle >= start || angle <= end;
  }
};

const calculateAngle = (currentCenter, nextCenter) => {
  const deltaX = nextCenter.x - currentCenter.x;
  const deltaY = nextCenter.y - currentCenter.y;
  let angle = Math.atan2(deltaY, deltaX);

  if (angle < 0) {
    angle += 2 * Math.PI; // 将负角度转换为正角度
  }

  return angle;
};
const changeFocus = (currentIndex, nextIndex) => {
  onItemBlur(currentIndex);
  focusId = nextIndex;
  onItemFocus(nextIndex);
};
const _moveToNext = (direction) => {
  const currentIndex = focusId;
  let nextIndex = -1;
  let centerList = [];
  let minDistance = Infinity;
  //中心点创建数组管理
  innerData.forEach((item, index) => {
    centerList.push({
      x: item.customerData.left + item.customerData.width / 2,
      y: item.customerData.top + item.customerData.height / 2,
    });
  });
  const currentCenter = centerList[currentIndex];
  const angleRange = getAngleRange(direction);

  for (let i = 0; i < centerList.length; i++) {
    if (i === currentIndex) continue; // 跳过当前聚焦的元素
    const nextCenter = centerList[i];
    const angle = calculateAngle(currentCenter, nextCenter);
    const distance = calculateDistance(currentCenter, nextCenter);
    if (
      isMovingInDirection(currentCenter, nextCenter, direction) &&
      isAngleInRange(angle, angleRange) &&
      distance < minDistance
    ) {
      minDistance = distance;
      nextIndex = i;
    }
  }
  if (nextIndex !== -1) {
    // 移动焦点到距离最短的元素
    changeFocus(currentIndex, nextIndex);
  } else {
    props?.onEdge();
  }
};

const _appointToNext = (direction) => {
  const currentIndex = focusId;
  let nextIndex;
  switch (direction) {
    case "up":
      nextIndex = innerData[currentIndex].customerData.SpecIndex.up;
      changeFocus(currentIndex, nextIndex);
      break;
    case "left":
      nextIndex = innerData[currentIndex].customerData.SpecIndex.left;
      changeFocus(currentIndex, nextIndex);
      break;
    case "down":
      nextIndex = innerData[currentIndex].customerData.SpecIndex.down;
      changeFocus(currentIndex, nextIndex);
      break;
    case "right":
      nextIndex = innerData[currentIndex].customerData.SpecIndex.right;
      changeFocus(currentIndex, nextIndex);
      break;
    default:
      return false;
  }
};
const calculateDistance = (currentCenter, nextCenter) => {
  const deltaX = nextCenter.x - currentCenter.x;
  const deltaY = nextCenter.y - currentCenter.y;
  return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
};
const isMovingInDirection = (currentCenter, nextCenter, direction) => {
  switch (direction) {
    case "up":
      return nextCenter.y < currentCenter.y;
    case "left":
      return nextCenter.x < currentCenter.x;
    case "down":
      return nextCenter.y > currentCenter.y;
    case "right":
      return nextCenter.x > currentCenter.x;
    default:
      return false;
  }
};
const focusBlockOnKeyDown = (ev) => {
  if (onKeyDownLock) {
    return true;
  }
  switch (ev.keyCode) {
    case 37:
      if (
        innerData[focusId].customerData.SpecIndex &&
        innerData[focusId].customerData.SpecIndex.left >= 0
      ) {
        _appointToNext("left");
      } else {
        _moveToNext("left");
      }
      break;
    case 38:
      if (
        innerData[focusId].customerData.SpecIndex &&
        innerData[focusId].customerData.SpecIndex.up >= 0
      ) {
        _appointToNext("up");
      } else {
        _moveToNext("up");
      }
      break;
    case 39:
      if (
        innerData[focusId].customerData.SpecIndex &&
        innerData[focusId].customerData.SpecIndex.right >= 0
      ) {
        _appointToNext("right");
      } else {
        _moveToNext("right");
      }
      break;
    case 40:
      if (
        innerData[focusId].customerData.SpecIndex &&
        innerData[focusId].customerData.SpecIndex.down >= 0
      ) {
        _appointToNext("down");
      } else {
        _moveToNext("down");
      }
      break;
    case 13:
      onItemClick(focusId);
      break;
    default:
      //只接受上下左右确定键
      return false;
  }
  return true;
};
//循环遍历传入的数组造innerData的数据
props.data.forEach((item, index) => {
  draw(item);
});

//焦点管理
const focusBlockOnFocus = () => {
  isFocus = true;
  preFocusId = -1;
  if (innerData.length === 0) {
    console.log(`MetroWidget: ${props.name} get focus while data is empty.`);
    return;
  }
  if (props.initFocusId < 0 || props.initFocusId > innerData.length - 1) {
    console.error("initFocusId无效！");
  }
  let focus_id = props.initFocusId ? props.initFocusId : 0;
  focusId = focus_id;
  onItemFocus(focusId);
  props.onFocus?.();
};

const focusBlockOnBlur = () => {
  isFocus = false;
  preFocusId = focusId;
  onItemBlur(preFocusId);
  props.onBlur?.();
};
</script>

<style lang="scss" scoped></style>
