<template>
  <div class="mtp-echats-kline">
    <div class="mtp-echats-kline__container main">
      <ul class="legend">
        <li class="legend-item">开: {{klineDetail ? klineDetail.open : '--'}}</li>
        <li class="legend-item">收: {{klineDetail ? klineDetail.close : '--'}}</li>
        <li class="legend-item">高: {{klineDetail ? klineDetail.highest : '--'}}</li>
        <li class="legend-item">低: {{klineDetail ? klineDetail.lowest : '--'}}</li>
        <li class="legend-item">MA5: {{klineDetail ? klineDetail.ma5 : '--'}}</li>
        <li class="legend-item">MA10: {{klineDetail ? klineDetail.ma10 : '--'}}</li>
        <li class="legend-item">MA15: {{klineDetail ? klineDetail.ma15 : '--'}}</li>
      </ul>
      <mtp-echarts :option="klineOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading" @ready="mainReady" />
    </div>
    <template v-if="showIndicator">
      <div class="mtp-echats-kline__container indicator">
        <!-- MACD -->
        <section class="section" v-if="activeSeriesType === SeriesType.MACD">
          <ul class="legend">
            <li class="legend-item">MACD: {{macdDetail ? macdDetail.macd : '--'}}</li>
            <li class="legend-item">DIF: {{macdDetail ? macdDetail.dif : '--'}}</li>
            <li class="legend-item">DEA: {{macdDetail ? macdDetail.dea : '--'}}</li>
          </ul>
          <mtp-echarts :option="macdOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading" @ready="indicatorReady" />
        </section>
        <!-- VOL -->
        <section class="section" v-if="activeSeriesType === SeriesType.VOL">
          <ul class="legend">
            <li class="legend-item">VOL: {{volDetail ? volDetail.vol : '--'}}</li>
          </ul>
          <mtp-echarts :option="volOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading" @ready="indicatorReady" />
        </section>
        <!-- KDJ -->
        <section class="section" v-if="activeSeriesType === SeriesType.KDJ">
          <ul class="legend">
            <li class="legend-item">K: {{kdjDetail ? kdjDetail.k : '--'}}</li>
            <li class="legend-item">D: {{kdjDetail ? kdjDetail.d : '--'}}</li>
            <li class="legend-item">J: {{kdjDetail ? kdjDetail.j : '--'}}</li>
          </ul>
          <mtp-echarts :option="kdjOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading" @ready="indicatorReady" />
        </section>
        <!-- CCI -->
        <section class="section" v-if="activeSeriesType === SeriesType.CCI">
          <ul class="legend">
            <li class="legend-item">CCI: {{cciDetail ? cciDetail.cci : '--'}}</li>
          </ul>
          <mtp-echarts :option="cciOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading" @ready="indicatorReady" />
        </section>
      </div>
      <mtp-tabbar theme="menu" :data="tabs" @change="tabChange" />
    </template>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, PropType, watch, computed } from 'vue'
import { QueryHistoryDatas, QueryQuoteDayRsp } from '@/services/go/quote/interface';
import { QueryHistoryDatas as queryHistoryDatas } from '@/services/go/quote';
import { getQuoteDayInfoByCode } from '@/services/bus/goods';
import { throttle } from '@/utils/time'
import { CycleType, SeriesType } from './type'
import { useDataset } from './dataset'
import { useOptions } from './options'
import moment from 'moment';
import * as echarts from 'echarts'
import MtpEcharts from '../echarts-base/index.vue'
import MtpTabbar from '../../tabbar/index.vue'
import { Tabbar } from '../../tabbar/type'

export default defineComponent({
  components: {
    MtpEcharts,
    MtpTabbar,
  },
  props: {
    goodscode: {
      type: String,
      default: '',
    },
    // 周期类型
    cycleType: {
      type: Number as PropType<CycleType>,
      default: CycleType.minutes,
    },
    // 是否显示指标
    showIndicator: {
      type: Boolean,
      default: true,
    },
  },
  setup(props) {
    const loading = ref(false),
      showEmpty = ref(false),
      dataIndex = ref(0), // 当前数据索引值
      activeSeriesType = ref(SeriesType.MACD), // 当前选中的指标
      chartGroup = new Map<string, echarts.ECharts>(), // 图表联动实例组
      quote = ref<QueryQuoteDayRsp>(getQuoteDayInfoByCode(props.goodscode)!); // 商品实时行情

    const { klineData, macdData, volData, kdjData, cciData, handleData, calcIndicator } = useDataset();
    const { klineOption, macdOption, volOption, kdjOption, cciOption, initOptions, updateOptions } = useOptions(klineData, macdData, volData, kdjData, cciData);
    const klineDetail = computed(() => klineData.source[dataIndex.value]);
    const macdDetail = computed(() => macdData.source[dataIndex.value]);
    const volDetail = computed(() => volData.source[dataIndex.value]);
    const kdjDetail = computed(() => kdjData.source[dataIndex.value]);
    const cciDetail = computed(() => cciData.source[dataIndex.value]);

    const tabs: Tabbar[] = [
      { label: 'MACD', value: SeriesType.MACD },
      { label: 'VOL', value: SeriesType.VOL },
      { label: 'KDJ', value: SeriesType.KDJ },
      { label: 'CCI', value: SeriesType.CCI },
    ]

    const mainReady = (chart: echarts.ECharts) => {
      chartGroup.set('main', chart);
      initData();
    }

    const indicatorReady = (chart: echarts.ECharts) => {
      chartGroup.delete('indicator');
      chartGroup.set('indicator', chart);
      echarts.connect([...chartGroup.values()]); // 图表联动
    }

    // 初始化数据
    const initData = () => {
      showEmpty.value = false;
      loading.value = true;
      dataIndex.value = -1;
      klineData.source = [];
      macdData.source = [];
      volData.source = [];
      kdjData.source = [];
      cciData.source = [];

      const params: QueryHistoryDatas = {
        cycleType: props.cycleType,
        goodsCode: props.goodscode.toUpperCase(),
        count: 1440,
      };

      // 查询历史数据
      queryHistoryDatas(params).then((res) => {
        if (res.length) {
          dataIndex.value = res.length - 1;
          // 日期升序排序
          const data = res.sort((a, b) => moment(a.ts).valueOf() - moment(b.ts).valueOf());
          handleData(data);
          initOptions();
        } else {
          showEmpty.value = true;
        }
      }).catch((err) => {
        console.error(err);
        showEmpty.value = true;
      }).finally(() => {
        loading.value = false;
      });
    }

    // 指标切换
    const tabChange = (item: Tabbar<SeriesType>) => {
      activeSeriesType.value = item.value;
      setTimeout(() => {
        initOptions();
      }, 0);
    }

    // 获取周期毫秒数
    const getCycleMilliseconds = () => {
      const milliseconds = 60 * 1000; // 一分钟毫秒数
      switch (props.cycleType) {
        case CycleType.minutes5: {
          return milliseconds * 5;
        }
        case CycleType.minutes30: {
          return milliseconds * 30;
        }
        case CycleType.minutes60: {
          return milliseconds * 60;
        }
        case CycleType.hours2: {
          return milliseconds * 2 * 60;
        }
        case CycleType.Hours4: {
          return milliseconds * 4 * 60;
        }
        case CycleType.days: {
          return milliseconds * 24 * 60;
        }
        default: {
          return milliseconds;
        }
      }
    }

    // 更新图表数据
    const updateChartData = () => {
      const { source } = klineData,
        lastIndex = source.length - 1, // 历史行情最后索引位置
        cycleMilliseconds = getCycleMilliseconds(),
        newTime = moment(quote.value.lasttime), // 实时行情最新时间
        newPrice = quote.value.last; // 实时行情最新价

      const oldTime = lastIndex === -1 ? newTime : moment(source[lastIndex].date); // 历史行情最后时间
      const diffTime = newTime.valueOf() - oldTime.valueOf(); // 计算时间差

      if (diffTime > cycleMilliseconds * 2) {
        // 时间间隔超过两个周期，重新请求历史数据
      } else {
        // 判断时间差是否大于周期时间
        if (lastIndex === -1 || diffTime > cycleMilliseconds) {
          oldTime.add(cycleMilliseconds, 'ms');
          const newDate = oldTime.format('YYYY-MM-DD HH:mm:ss');

          // 新增K线数据
          klineData.source.push({
            date: newDate,
            open: newPrice,
            close: newPrice,
            lowest: newPrice,
            highest: newPrice,
            ma5: '-',
            ma10: '-',
            ma15: '-',
          });

          // 新增MACD数据
          macdData.source.push({
            date: newDate,
            ema12: 0,
            ema26: 0,
            dif: 0,
            dea: 0,
            macd: 0,
          })

          // 新增VOL数据
          volData.source.push({
            date: newDate,
            vol: 0,
          })

          // 新增KDJ数据
          kdjData.source.push({
            date: newDate,
            k: '-',
            d: '-',
            j: '-',
          })

          // 新增CCI数据
          cciData.source.push({
            date: newDate,
            cci: '-',
          })
        } else {
          // 更新列表中最后一条记录的数据
          const item = source[lastIndex];
          if (item.lowest > newPrice) {
            item.lowest = newPrice; // 更新最低价
          }
          if (item.highest < newPrice) {
            item.highest = newPrice; // 更新最高价
          }
          item.close = newPrice; // 更新收盘价
        }

        // 更新各种指标
        calcIndicator(lastIndex === -1 ? 0 : lastIndex);

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

    // 监听行情推送
    watch(() => quote.value.last, () => {
      if (!loading.value) {
        updateChartData();
      }
    })

    // 监听周期选择变化
    watch(() => props.cycleType, () => initData());

    return {
      SeriesType,
      loading,
      showEmpty,
      dataIndex,
      tabs,
      activeSeriesType,
      klineData,
      klineOption,
      macdOption,
      volOption,
      kdjOption,
      cciOption,
      klineDetail,
      macdDetail,
      volDetail,
      kdjDetail,
      cciDetail,
      tabChange,
      mainReady,
      indicatorReady,
    }
  }
})
</script>

<style lang="less">
@import './index.less';
</style>