<template>
  <div
    class="w-full"
    :class="{
      'h-48': !props.data,
      'h-150': props.data,
    }"
  >
    <v-chart
      v-if="props.data"
      class="w-full h-full"
      :option="option"
      autoresize
      :update-options="updateOptions"
    />
    <div
      v-else
      class="w-full h-full flex flex-col gap-6 items-center justify-center"
    >
      <template v-if="hasSlot">
        <slot />
      </template>
      <template v-else>
        <div class="text-center">
          <h3 class="text-xl font-semibold text-slate-600 mb-2">暂无数据</h3>
        </div>
      </template>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, shallowRef, useSlots } from "vue";
import VChart from "vue-echarts";

// Echarts
import { use } from "echarts/core";
import { LineChart } from "echarts/charts";
import {
  TooltipComponent,
  GridComponent,
  DataZoomComponent,
  AxisPointerComponent,
  ToolboxComponent,
  MarkLineComponent,
} from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
import type { ComposeOption } from "echarts/core";
import type { LineSeriesOption } from "echarts/charts";
import type {
  AxisPointerComponentOption,
  TooltipComponentOption,
  GridComponentOption,
  DataZoomComponentOption,
  MarkLineComponentOption,
} from "echarts/components";
import type {
  ToolboxComponentOption,
  XAXisOption,
  YAXisOption,
} from "echarts/types/dist/shared";
import { isUndefined } from "lodash";
import type { LogicDataType } from ".";

use([
  TooltipComponent,
  ToolboxComponent,
  GridComponent,
  AxisPointerComponent,
  DataZoomComponent,
  LineChart,
  CanvasRenderer,
  MarkLineComponent,
]);

type EChartsOption = ComposeOption<
  | AxisPointerComponentOption
  | TooltipComponentOption
  | ToolboxComponentOption
  | GridComponentOption
  | DataZoomComponentOption
  | LineSeriesOption
  | MarkLineComponentOption
>;

const props = defineProps<{
  data?: LogicDataType;
}>();

const slots = useSlots();
const hasSlot = computed(() => !!slots.default && slots.default().length > 0);

// 添加更新选项来减少重绘
const updateOptions = shallowRef({
  notMerge: false,
  lazyUpdate: true,
  silent: false,
});

const option = computed((): EChartsOption => {
  if (isUndefined(props.data)) return {};

  // 只获取启用的通道，使用y数据结构
  const enabledChannels = props.data.y.filter(
    (channel) => channel.enabled,
  );
  const enabledChannelIndices = props.data.y
    .map((channel, index) => (channel.enabled ? index : -1))
    .filter((index) => index !== -1);

  // 统计启用通道数量
  const channelCount = enabledChannels.length;
  const channelSpacing = 2; // 每个通道之间的间距

  if (channelCount === 0) {
    return {};
  }

  // 单个网格
  const grids: GridComponentOption[] = [
    {
      left: "5%",
      right: "5%",
      top: "5%",
      bottom: "15%",
    },
  ];

  // 单个X轴
  const xAxis: XAXisOption[] = [
    {
      type: "category",
      boundaryGap: true,
      data: props.data.x.map((x) => x.toFixed(3)),
      axisLabel: {
        formatter: (value: string) =>
          props.data
            ? `${value}${props.data.xUnit}`
            : `${value}`,
      },
    },
  ];

  // 单个Y轴，范围根据启用通道数量调整
  const yAxis: YAXisOption[] = [
    {
      type: "value",
      min: -0.5,
      max: channelCount * channelSpacing - 0.5,
      interval: channelSpacing,
      axisLabel: {
        formatter: (value: number) => {
          const channelIndex = Math.round(value / channelSpacing);
          return channelIndex < channelCount
            ? enabledChannels[channelIndex].name
            : "";
        },
      },
      splitLine: { show: false },
    },
  ];

  // 创建系列数据
  const series: LineSeriesOption[] = [];
  enabledChannelIndices.forEach(
    (originalIndex: number, displayIndex: number) => {
      const channel = props.data!.y[originalIndex];
      if (channel.type === "logic") {
        // logic类型，原样显示
        series.push({
          name: channel.name,
          type: "line",
          data: channel.value.map(
            (value: number) => value + displayIndex * channelSpacing + 0.2,
          ),
          step: "end",
          lineStyle: {
            width: 2,
            color: channel.color,
          },
          areaStyle: {
            opacity: 0.3,
            origin: displayIndex * channelSpacing,
            color: channel.color,
          },
          symbol: "none",
          sampling: "lttb",
          animation: false,
        });
      } else if (channel.type === "number") {
        const values = channel.value;
        const xArr = props.data!.x;
        // 构造带过渡的点序列
        function buildVcdLine(valArr: number[], high: number, low: number) {
          const points: { x: number; y: number }[] = [];
          let lastValue = high;
          points.push({ x: xArr[0], y: lastValue });
          for (let i = 1; i < valArr.length; i++) {
            const v =
              valArr[i] !== valArr[i - 1]
                ? lastValue === high
                  ? low
                  : high
                : lastValue;
            points.push({ x: xArr[i], y: v });
            lastValue = v;
          }
          return points.map((p) => p.y);
        }

        // 计算变化点区间
        function buildMarkLines(valArr: number[], yBase: number) {
          const markLines: any[] = [];
          let lastValue = valArr[0];
          let lastIdx = 0;
          // 格式化函数
          function formatValue(val: number) {
            if (channel.base === "hex")
              return "0x" + val.toString(16).toUpperCase();
            if (channel.base === "bin") return "0b" + val.toString(2);
            return val.toString();
          }
          for (let i = 1; i <= valArr.length; i++) {
            if (i === valArr.length || valArr[i] !== lastValue) {
              markLines.push([
                {
                  xAxis: lastIdx,
                  yAxis: yBase,
                  label: {
                    formatter: formatValue(lastValue),
                    position: "insideMiddle",
                    color: channel.color,
                    fontSize: 18,
                    opacity: 1,
                  },
                  lineStyle: {
                    opacity: 0,
                  },
                },
                {
                  xAxis: i - 1,
                  yAxis: yBase,
                  lineStyle: {
                    opacity: 0,
                  },
                },
              ]);
              lastValue = valArr[i];
              lastIdx = i;
            }
          }
          return markLines;
        }

        // 1线条
        series.push({
          name: channel.name + "_1",
          type: "line",
          data: buildVcdLine(
            values,
            displayIndex * channelSpacing + 1,
            displayIndex * channelSpacing,
          ),
          step: false,
          lineStyle: {
            width: 2,
            color: channel.color,
          },
          areaStyle: {
            opacity: 0.3,
            origin: displayIndex * channelSpacing + 0.5,
            color: channel.color,
          },
          symbol: "none",
          sampling: "lttb",
          animation: false,
          // 添加markLine
          markLine: {
            data: buildMarkLines(values, displayIndex * channelSpacing + 0.5),
            emphasis: {
              disabled: true,
            },
          },
        });
        // 0线条
        series.push({
          name: channel.name + "_0",
          type: "line",
          data: buildVcdLine(
            values,
            displayIndex * channelSpacing,
            displayIndex * channelSpacing + 1,
          ),
          step: false,
          lineStyle: {
            width: 2,
            color: channel.color,
          },
          areaStyle: {
            opacity: 0.3,
            origin: displayIndex * channelSpacing + 0.5,
            color: channel.color,
          },
          symbol: "none",
          sampling: "lttb",
          animation: false,
        });
      }
    },
  );

  return {
    animation: false,
    tooltip: {
      trigger: "axis",
      axisPointer: {
        type: "line",
        label: {
          backgroundColor: "#6a7985",
        },
        animation: false,
      },
      formatter: (params: any) => {
        if (Array.isArray(params) && params.length > 0) {
          const timeValue = props.data!.x[params[0].dataIndex];
          const dataIndex = params[0].dataIndex;
          let tooltip = `Time: ${timeValue.toFixed(3)}${props.data!.xUnit}<br/>`;
          enabledChannelIndices.forEach(
            (originalIndex: number, displayIndex: number) => {
              const channel = props.data!.y[originalIndex];
              if (channel.type === "logic") {
                const channelName = channel.name;
                const originalValue = channel.value[dataIndex];
                tooltip += `${channelName}: ${originalValue}<br/>`;
              } else if (channel.type === "number") {
                const channelName = channel.name;
                const originalValue = channel.value[dataIndex];
                tooltip += `${channelName}: ${originalValue}<br/>`;
              }
            },
          );
          return tooltip;
        }
        return "";
      },
      hideDelay: 100,
    },
    toolbox: {
      feature: {
        restore: {},
      },
    },
    grid: grids,
    xAxis: xAxis,
    yAxis: yAxis,
    dataZoom: [
      {
        show: true,
        realtime: true,
        start: 0,
        end: 100,
      },
      {
        type: "inside",
        realtime: true,
        start: 0,
        end: 100,
      },
    ],
    series: series,
  };
});
</script>
