<template>
  <div ref="chartRef" :style="{ width: width, height: height }"></div>
</template>

<script setup>
import { ref, watch, onMounted, nextTick } from 'vue';
import { cloneDeep } from 'lodash';
import { useEcharts } from '@/hooks/useEcharts';

defineOptions({ name: 'NewHyalineCake' });

// 定义组件 props
const props = defineProps({
  chartData: {
    type: Array,
    default: () => [
      // 默认示例数据
      { name: '项目一', value: 60 },
      { name: '项目二', value: 44 },
      { name: '项目三', value: 32 },
    ],
  },
  option: {
    type: Object,
    default: () => ({
      // 控制内外径关系的系数，1 表示无内径（实心饼），值越小内径越大
      k: 1,
      // 扇形边缘向外偏移距离比例（用于选中效果），单位视图坐标，可调
      itemGap: 0.2,
      // 扇形高度（影响z轴拉伸程度）
      itemHeight: 120,
      // 自动计算扇形高度时使用的系数（>0时 itemHeight 失效，使用 autoItemHeight * value ）
      autoItemHeight: 0,
      // 透明度设置
      opacity: 0.6,
      // 图例后缀
      legendSuffix: '',
    }),
  },
  width: {
    type: String,
    default: '100%',
  },
  height: {
    type: String,
    default: '100%',
  },
});

// 声明组件触发的事件
const emit = defineEmits(['click']);

// 绑定到DOM的容器引用
const chartRef = ref(null);
// 使用 useEcharts 钩子初始化 ECharts 实例，并获取控制方法
const { setOptions, getInstance } = useEcharts(chartRef);

// 存储当前的 ECharts 配置项
const chartOption = ref({});

// 参数方程函数：生成每个扇形曲面的参数方程，用于 series-surface.parametricEquation
function getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
  // 中心弧度用于计算偏移方向
  const midRatio = (startRatio + endRatio) / 2;
  const startRadian = startRatio * Math.PI * 2;
  const endRadian = endRatio * Math.PI * 2;
  const midRadian = midRatio * Math.PI * 2;

  // 如果整个饼只剩一个扇形，则不实现选中效果
  if (startRatio === 0 && endRatio === 1) {
    isSelected = false;
  }
  // k 取默认值 1/3（环的厚度比例），如果传入 k 则使用传入值
  k = typeof k !== 'undefined' ? k : 1 / 3;

  // 计算选中效果的偏移量（基于扇形中心角度）
  const offsetX = isSelected ? Math.cos(midRadian) * props.option.itemGap : 0;
  const offsetY = isSelected ? Math.sin(midRadian) * props.option.itemGap : 0;
  // 计算高亮时的放大比例（未高亮时为1）
  const hoverRate = isHovered ? 1.05 : 1;

  // 返回 parametric 曲面方程
  return {
    u: {
      // u 参数控制饼的周向角度：从 -π 到 3π，可以完整绘制一圈
      min: -Math.PI,
      max: Math.PI * 3,
      step: Math.PI / 32,
    },
    v: {
      // v 从 0 - 2π 参数控制扇形的径向方向（厚度方向）
      min: 0,
      max: Math.PI * 2,
      step: Math.PI / 20,
    },
    x(u, v) {
      // 如果在起始弧度之前，保持扇形起点的半径
      if (u < startRadian) {
        return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      // 如果在结束弧度之后，保持扇形终点的半径
      if (u > endRadian) {
        return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      // 扇形中间部分正常绘制
      return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
    },
    y(u, v) {
      if (u < startRadian) {
        return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      if (u > endRadian) {
        return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
    },
    z(u, v) {
      // 在 u < -π/2 时，防止出现不必要的翻转，直接使用基本正弦
      if (u < -Math.PI * 0.5) {
        return Math.sin(u);
      }
      // 在 u > 2.5π 时，处理扇形尾部厚度
      if (u > Math.PI * 2.5) {
        return Math.sin(u) * h * 0.1;
      }
      // 正常情况下，z 根据 v 参数控制上下表面的高度差
      // 当前图形的高度是Z根据h（每个value的值决定的）
      return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
    },
  };
}

// 生成整个 3D 饼图的配置项
function getPie3D(pieData) {
  const series = [];
  let sumValue = 0;
  // 计算总值
  pieData.forEach((item) => {
    sumValue += item.value;
  });

  // k 为外径厚度系数
  const k = props.option.k ?? 1;
  // 构建每个扇形的 series 数据
  pieData.forEach((dataItem, idx) => {
    const seriesItem = {
      name: dataItem.name ?? `series${idx}`,
      type: 'surface',
      parametric: true,
      wireframe: { show: false },
      pieData: dataItem,
      itemStyle: {
        opacity: props.option.opacity,
        borderRadius: 300,
        borderColor: '#fff',
        borderWidth: 0,
      },
      pieStatus: {
        selected: false,
        hovered: false,
        k,
      },
    };
    // 合并自定义样式（如果有）
    if (dataItem.itemStyle) {
      const customStyle = {};
      if (dataItem.itemStyle.color !== undefined) {
        customStyle.color = dataItem.itemStyle.color;
      }
      if (dataItem.itemStyle.opacity !== undefined) {
        customStyle.opacity = dataItem.itemStyle.opacity;
      }
      seriesItem.itemStyle = { ...seriesItem.itemStyle, ...customStyle };
    }
    series.push(seriesItem);
  });

  // 计算每个扇形的 startRatio/endRatio 和参数方程
  let startValue = 0;
  series.forEach((serie) => {
    const endValue = startValue + serie.pieData.value;
    const startRatio = startValue / sumValue;
    const endRatio = endValue / sumValue;
    serie.pieData.startRatio = startRatio;
    serie.pieData.endRatio = endRatio;
    // 初始均为未选中未高亮
    serie.parametricEquation = getParametricEquation(
      startRatio,
      endRatio,
      false,
      true,
      k,
      // 扇形高度：根据配置自动计算或使用固定高度
      props.option.autoItemHeight > 0 ? props.option.autoItemHeight * serie.pieData.value : props.option.itemHeight
    );
    startValue = endValue;
  });

  // 添加一个透明圆环，用于实现 hover 在扇形外面时取消高亮
  series.push({
    name: 'mouseoutSeries',
    type: 'surface',
    parametric: true,
    wireframe: { show: false },
    itemStyle: { opacity: 0 },
    parametricEquation: {
      u: { min: 0, max: Math.PI * 2, step: Math.PI / 20 },
      v: { min: 0, max: Math.PI, step: Math.PI / 20 },
      x(u, v) {
        return Math.sin(v) * Math.sin(u) + Math.sin(u);
      },
      y(u, v) {
        return Math.sin(v) * Math.cos(u) + Math.cos(u);
      },
      z(u, v) {
        return Math.cos(v) > 0 ? 0.1 : -0.1;
      },
    },
  });

  // 基础配置：坐标轴、视角、图例、提示框等
  const option = Object.assign(
    {
      tooltip: {
        backgroundColor: 'rgba(18, 55, 85, 0.8)',
        borderColor: '#35d0c0',
        color: '#fff',
        position: (point, params, dom, rect, size) => {
          // 动态调整 tooltip 位置，避免溢出
          let x = point[0],
            y = point[1];
          const [viewW, viewH] = size.viewSize;
          const [boxW, boxH] = size.contentSize;
          if (x + boxW > viewW) x -= boxW;
          if (y + boxH > viewH) y -= boxH;
          if (x < 0) x = 0;
          if (y < 0) y = 0;
          return [x, y];
        },
        formatter: (params) => {
          // 只对非透明环（实际扇形）显示信息
          if (params.seriesName !== 'mouseoutSeries') {
            return `
            <span style="color:#FFF">
              ${params.seriesName}<br/>
              <span style="
                display:inline-block;
                margin-right:5px;
                border-radius:10px;
                width:10px;
                height:10px;
                background-color:${params.color};"></span>
              ${chartOption.value.series[params.seriesIndex].pieData.value}
            </span>`;
          }
          return '';
        },
      },
      xAxis3D: { min: -1, max: 1 },
      yAxis3D: { min: -1, max: 1 },
      zAxis3D: { min: -1, max: 1 },
      grid3D: {
        show: false,
        boxHeight: 5,
        top: '0',
        left: '-20%',
        viewControl: {
          // 3D 视角设置
          alpha: 60, // 俯仰角度
          distance: 240, // 视角距离
          rotateSensitivity: 10,
          zoomSensitivity: 10,
          panSensitivity: 10,
          autoRotate: true,
          autoRotateAfterStill: 2,
        },
      },
      legend: {
        show: true,
        selectedMode: false,
        right: '5%',
        top: '25%',
        orient: 'vertical',
        icon: 'circle',
        itemHeight: 12,
        itemWidth: 12,
        itemGap: 10,
        textStyle: {
          color: '#fff',
          fontSize: 14,
          fontWeight: '400',
        },
        // 图例标签显示名称和数值
        formatter: (name) => {
          const item = props.chartData.find((d) => d.name === name);
          return item ? `  ${name}      ${item.value}${props.option.legendSuffix || ''}` : name;
        },
      },
      series,
    },
    // 将外部配置项覆盖基础配置
    props.option
  );

  return option;
}

// 初始化图表
function initChart() {
  // 生成基础的3D饼图配置
  const baseOption = getPie3D(props.chartData);
  // 合并用户配置，确保不修改原始对象
  const finalOption = Object.assign({}, baseOption, cloneDeep(props.option || {}));
  chartOption.value = finalOption;
  // 设置图表配置
  setOptions(chartOption.value);
  // 等待 DOM + ECharts 初始化完成
  nextTick(() => {
    const chart = getInstance();
    if (!chart) {
      console.warn('ECharts 实例未初始化，事件绑定失败');
      return;
    }

    // 避免重复绑定事件
    chart.off('click');
    chart.off('mouseover');
    chart.off('globalout');

    chart.on('click', handleClick);
    chart.on('mouseover', handleMouseover);
    chart.on('globalout', handleGlobalout);
  });
}
function handleClick(params) {
  // 如果点击的是透明辅助环，则忽略
  if (params.seriesName === 'mouseoutSeries') return;

  const optionVal = chartOption.value;
  const series = optionVal.series;
  const idx = params.seriesIndex;

  // 新的选中状态（取反）
  const isSelected = !series[idx].pieStatus.selected;
  const isHovered = series[idx].pieStatus.hovered;
  const k = series[idx].pieStatus.k;
  const startRatio = series[idx].pieData.startRatio;
  const endRatio = series[idx].pieData.endRatio;
  const h = series[idx].pieData.value;

  // 如果之前有其他扇形被选中，取消其选中状态
  if (selectedIndex !== null && selectedIndex !== idx) {
    const prev = series[selectedIndex];
    prev.parametricEquation = getParametricEquation(
      prev.pieData.startRatio,
      prev.pieData.endRatio,
      false,
      false,
      prev.pieStatus.k,
      prev.pieData.value
    );
    prev.pieStatus.selected = false;
    selectedIndex = null;
  }

  // 设置当前扇形的选中/取消选中状态
  series[idx].parametricEquation = getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h);
  series[idx].pieStatus.selected = isSelected;

  // 更新记录选中的系列索引
  selectedIndex = isSelected ? idx : null;

  // 更新图表配置
  setOptions(optionVal);
  // 触发组件 click 事件供父组件使用
  emit('click', params);
}
// 在函数顶部声明（确保作用域覆盖所有需要的地方）
window.debugZValues = {
  current: null,
  history: [],
};
function handleMouseover(params) {
  if (params.seriesName === 'mouseoutSeries') return;

  const chart = getInstance();
  const optionVal = chart.getOption(); // 改用实时获取最新配置
  const series = optionVal.series;
  const idx = params.seriesIndex;
  const hh = series[idx].parametricEquation.z();
  window.debugZValues.current = hh;
  window.debugZValues.history.push({
    event: 'mouseover',
    series: series[idx].name,
    zValue: hh,
    time: new Date().toISOString(),
  });
  console.log('当前Z值:', hh, '历史记录:', window.debugZValues.history);
  // 打印移入前的完整状态（调试用）
  console.log(
    '[移入] 当前所有扇形状态',
    series.map((s) => ({
      name: s.name,
      hovered: s.pieStatus?.hovered,
      selected: s.pieStatus?.selected,
      height: s.parametricEquation?.z(Math.PI, Math.PI),
    }))
  );

  // 取消之前的高亮（确保只修改状态，不破坏参数方程）
  if (hoveredIndex !== null && hoveredIndex !== idx) {
    const prev = series[hoveredIndex];
    prev.pieStatus.hovered = false; // 仅修改状态
    prev.parametricEquation = getParametricEquation(
      // 重新生成正确方程
      prev.pieData.startRatio,
      prev.pieData.endRatio,
      prev.pieStatus.selected,
      false, // isHovered=false
      prev.pieStatus.k,
      prev.pieData.value
    );
  }

  // 设置新高亮
  const current = series[idx];
  current.pieStatus.hovered = true;
  current.parametricEquation = getParametricEquation(
    current.pieData.startRatio,
    current.pieData.endRatio,
    current.pieStatus.selected,
    true, // isHovered=true
    current.pieStatus.k,
    current.pieData.value
  );

  hoveredIndex = idx;
  chart.setOption({ series }); // 仅更新series部分
}
function handleGlobalout() {
  if (hoveredIndex !== null) {
    const chart = getInstance();
    const optionVal = chart.getOption();
    const series = optionVal.series;
    const prev = series[hoveredIndex];

    // 打印修复前的错误状态（调试用）
    console.warn('[修复前] 异常状态', {
      name: prev.name,
      z: prev.parametricEquation.z(Math.PI, Math.PI),
      equation: prev.parametricEquation,
    });

    // 重置状态并重新生成方程
    prev.pieStatus.hovered = false;
    prev.parametricEquation = getParametricEquation(
      prev.pieData.startRatio,
      prev.pieData.endRatio,
      prev.pieStatus.selected,
      false, // isHovered=false
      prev.pieStatus.k,
      prev.pieData.value
    );

    hoveredIndex = null;
    chart.setOption({ series }, { replaceMerge: 'series' }); // 强制替换series
  }
}
// 记录当前选中和高亮的系列索引
let selectedIndex = null;
let hoveredIndex = null;

// 组件挂载后绑定事件
onMounted(() => {
  initChart();
});

// 监听数据或配置变更，重新初始化图表
watch(
  [() => props.chartData, () => props.option],
  () => {
    if (props.chartData && props.chartData.length) {
      initChart();
    }
  },
  { immediate: true, deep: true }
);
</script>

<style scoped>
/* 可根据需要自定义图表容器样式 */
</style>
