<template>
  <echart-base :options="[options]" :empty="isEmpty" v-model:loading="loading"></echart-base>
</template>

<script lang="ts">
import { defineComponent, ref, watch, PropType, onMounted, computed } from 'vue';
import { QueryTSDataRsp, QueryQuoteDayRsp } from '@/services/go/quote/interface';
import { QueryTSData } from '@/services/go/quote';
import { _debounce, getRangeTime } from '@/utils/time';
import { toDecimalFull } from '@/utils/number';
import EchartBase from '../echart-base/index.vue';
import { handleEchart } from './setup';
import moment from 'moment';

export default defineComponent({
  name: 'EchartTime',
  emits: ['change'],
  components: {
    EchartBase,
  },
  props: {
    // 实时行情数据
    quoteData: {
      type: Object as PropType<QueryQuoteDayRsp>,
      required: true,
    },
  },
  setup(props, { emit }) {
    const loading = ref(false);
    const isEmpty = ref(false);
    const historyIndexs: number[] = []; // 行情历史数据中所有非补充数据的索引位置(用于计算均线)
    const { chartData, options, updateOptions, initOptions } = handleEchart();

    // 处理图表数据
    const handleData = (rawData: QueryTSDataRsp): void => {
      historyIndexs.length = 0; // 清空数据
      const datas: number[] = [],
        times: string[] = [],
        xAxisTimes: string[] = [],
        yestclose = rawData.preSettle,
        decimal = rawData.decimalPlace;

      // 历史行情日期
      rawData.historyDatas.forEach((item, index) => {
        const { c, ts } = item;
        datas.push(c);
        times.push(moment(ts).format('YYYY-MM-DD HH:mm:ss'));
        if (!item.f) historyIndexs.push(index);
      });

      // 时间轴(开盘交易时间)
      rawData.runSteps.forEach((item) => {
        const { start, end } = item;
        const rangeTime = getRangeTime(start, end, 'HH:mm', 'm');
        xAxisTimes.push(...rangeTime);
      });

      chartData.value = {
        yestclose,
        decimal,
        rawTime: times,
        ...calcDataLine(datas, yestclose),
        source: {
          time: xAxisTimes,
          data: datas,
          ma5: calcMA(datas, 5, decimal),
        },
      };
    };

    // 计算图表最高低指标线
    const calcDataLine = (datas: number[], yestclose: number) => {
      let max = Math.max(...datas); // 取历史行情最高价
      let min = Math.min(...datas); // 取历史行情最低价

      const last = datas[datas.length - 1], // 历史行情最后收盘价
        a = yestclose - min, // 计算收盘价和最低价的差值
        b = max - yestclose; // 计算收盘价和最高价的差值

      // 比较差值大小
      if (a > b) {
        max = yestclose + a;
        if (last > max) {
          const c = last - max;
          max += c;
          min -= c;
        }
      } else {
        min = min - (b - a);
        if (min > last) {
          const c = min - last;
          max += c;
          min -= c;
        }
      }

      return {
        max: max,
        min: min,
      };
    };

    // 计算平均线
    const calcMA = (data: number[], count: number, decimal: number) => {
      const result: string[] = [];
      if (data.length >= count) {
        // 均线起始位置
        const startIndex = historyIndexs[count - 1];
        for (let i = 0; i < data.length; i++) {
          if (startIndex === undefined || i < startIndex) {
            result.push('-');
          } else {
            const j = historyIndexs.findIndex((val) => val === i);
            // 判断是否补充数据
            if (j === -1) {
              // 取上个平均值
              result.push(result[result.length - 1]);
            } else {
              // 向后取MA数
              const maIndexs = historyIndexs.slice(j - (count - 1), j + 1);
              // 计算总价
              const total = maIndexs.reduce((sum, val) => sum + data[val], 0);
              // 计算均线
              const ma = toDecimalFull(total / count, decimal);
              result.push(ma);
            }
          }
        }
      }
      return result;
    };

    // 更新分时数据
    const updateChartData = () => {
      const { source, rawTime } = chartData.value,
        lastIndex = source.data.length - 1, // 历史行情最后索引位置
        lastTime = moment(rawTime[rawTime.length - 1]), // 历史行情最后时间
        newTime = moment(props.quoteData.lasttime), // 实时行情最新时间
        newPrice = props.quoteData.last; // 实时行情最新价

      const cycleMilliseconds = 60 * 1000; // 周期毫秒数

      const diffTime = newTime.valueOf() - lastTime.valueOf(); // 计算时间差
      // 判断时间差是否大于周期时间
      if (diffTime > cycleMilliseconds) {
        lastTime.add(cycleMilliseconds, 'ms');
        rawTime.push(lastTime.format('YYYY-MM-DD HH:mm:ss')); // 添加历史行情时间
        source.data.push(newPrice); // 添加历史行情数据
        historyIndexs.push(lastIndex + 1); // 添加历史行情索引
      } else {
        source.data[lastIndex] = newPrice; // 更新历史行情数据
      }

      source.ma5 = calcMA(source.data, 5, chartData.value.decimal);

      const { min, max } = calcDataLine(source.data, chartData.value.yestclose);
      chartData.value.min = min;
      chartData.value.max = max;

      // 延迟图表更新，减少卡顿
      _debounce(() => {
        updateOptions();
      }, 1000);
    };

    onMounted(() => {
      loading.value = true;
      // 查询分时数据
      QueryTSData(props.quoteData.goodscode)
        .then((res) => {
          if (res.historyDatas.length) {
            isEmpty.value = false;
            handleData(res);
            // 调用父级函数查询tik数据 (不合理的逻辑处理，待优化)
            emit('change', res.startTime, res.endTime);
          } else {
            isEmpty.value = true;
          }
          initOptions();
        })
        .catch(() => {
          isEmpty.value = true;
        })
        .finally(() => {
          loading.value = false;
        });
    });

    watch(
      () => props.quoteData.last,
      () => {
        if (!loading.value) {
          updateChartData();
        }
      }
    );

    return {
      loading,
      isEmpty,
      options,
    };
  },
});
</script>