<!--  -->
<template>
  <div class="chart-show">
    <header class="chart-header" @click="openNew">
      <span class="chart-title">{{ chartInfo.ChartName }}</span>
    </header>
    <template v-if="haveData">
      <div
        class="chart-wrapper"
        id="chart-wrapper"
        v-loading="loading"
        element-loading-spinner="el-icon-loading"
        element-loading-text="加载中..."
      >
        <chart :options="options" :chartId="chartInfo.ChartInfoId || 0" />
        <div class="mark"></div>
      </div>
    </template>
    <div class="chart-wrapper notfound" v-else>
      <i class="el-icon-warning"></i>哎吆，你的图飞了，赶快去找管理员救命吧~
    </div>
    <div class="bootom-source">
      <strong style="flex-shrink: 0;">source:  <em> {{sourceName}}弘则研究</em></strong>
      <ul class="right-action" @click.stop>
        <li @click="copyUrl" class="copy" v-if="isShare"><i class="el-icon-share"/>分享</li>
        <li @click="refreshChart"><i class="el-icon-refresh"/>刷新</li>
      </ul>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs, onMounted, ref } from 'vue';
import { ElMessage } from 'element-plus';
import _ from 'lodash';
import { useRoute } from 'vue-router';
import chart from '@/components/chart.vue';
import { IState } from './typing';
import { ChartApi } from '@/request/api';
import { IChartType, IDataProps, ILunarItem, IParams, ISeasonDataItemProps } from '@/types';
import Highcharts from 'highcharts';
import { defaultOpts, seasonOptions } from '@/utils/chartOptions';
import moment from 'moment';

// 散点x
const scatterXAxis = {
  tickPosition: 'inside',
  lineColor: '#bfbfbf',
  tickColor: '#bfbfbf',
  tickLength:5,
  ordinal: false,
  type: 'linear',
}

//基础y轴
const basicYAxis = {
  tickLength:5,
  lineWidth: 1,
  lineColor: '#bfbfbf',
  tickColor: '#bfbfbf',
  // offset: 0,
  visible: true,
  gridLineWidth: 0,
  tickPosition: 'inside',
  endOnTick: false,
  startOnTick: false,
  showLastLabel: true
}

export default defineComponent({
  components: {
    chart,
  },
  setup() {
    const route = useRoute();

    const loading = ref(false);

    const haveData = ref(true);

    const code = ref(route.query.code);
    const isShare = ref(route.query.fromType === 'share');
    const screen = ref(document.body.clientWidth < 1200 ? 'phone' : 'pc');

    const state = reactive<IState>({
      options: {},
      chartInfo: {},
      dataList: [],
      sourceName: ''
    });

    onMounted((): void => {
      getChartInfo();
    });

    // 打开新窗口
    const openNew = (): void => {
			window.open(window.location.href,'_blank');
    }

    /* 处理图表来源 只限第三方 */
    const dealSourceHandle = (): void => {

      // 取出第三方来源 
      const arr = state.dataList.filter(item => item.EdbType === 1 && item.Source!== 9).map(item => ({
          key: item.Source,
          name: item.SourceName,
        })
      );

      let res_arr = arr.length ? _.uniqBy(arr,'key') : [];

      let str = '';
      res_arr.forEach((item: any) => {
        str += `${item.name}, `
      })
      state.sourceName = str;
    }

    /* 获取图表数据信息 */
    const getChartInfo = async (type='') => {
      loading.value = true;
      try {
        const { Data } = await ChartApi.getChart({
          UniqueCode: code.value || '',
        });
        loading.value = false;
        state.chartInfo = Data.ChartInfo;
        state.dataList = Data.EdbInfoList;
        document.title = Data.ChartInfo.ChartName;
        haveData.value = true;
        dealSourceHandle();
        setOptions();
        type === 'refresh' && ElMessage.success('刷新成功');
      }catch (e) {
        loading.value = false;
        haveData.value = false;
      }

    };

    // 曲线图x轴显示计算年限差 >1年 显示年/月 <=1 显示月/日
    const xTimeDiffer = () => {
      const end_date = state.chartInfo.DateType === 5
        ? state.chartInfo.EndDate
        : state.chartInfo.DateType === 6
        ? new Date()
        : '';
      //年限差
      const year_differ = moment(end_date).diff(
        moment(state.chartInfo.StartDate),
        'years',
        true
      );
      // console.log(year_differ)
      if ([5, 6].includes(state.chartInfo.DateType) && year_differ <= 1) {
        return true
      } else {
        return false
      }
    }

    /* 曲线图 */
    const setDefaultLineOptions = () => {
      const { dataList,chartInfo } = state;

      //拼接标题 数据列
      let data = [] as any[],ydata = [] as any[],minTimeArr: number[] = [],maxTimeArr: number[] = [];
      // const chartData = _.cloneDeep(dataList);
       //有右二轴时排个序 按照左 右 右2的顺序
      let chartData = dataList.some(_ =>_.IsAxis===2) ? changeEdbOrder(dataList) : _.cloneDeep(dataList);
      
      chartData.forEach((item:IDataProps ,index:number) => {

        //轴位置值相同的下标
        let sameSideIndex = chartData.findIndex(
          (i:IDataProps) => i.IsAxis === item.IsAxis
        );
        //y轴
        let yItem = {
          ...basicYAxis,
          labels: {
            formatter: function (ctx: any) {
              let val = Math.abs(ctx.value) < 1000 ? ctx.value :  ctx.value / 1000 + 'k';
              return sameSideIndex !== index ? '' : val;
            },
            align: 'center',
            x: [0,2].includes(item.IsAxis) ? 5 : -5,
            style: {
              fontSize: '10px',
            },
          },
          title: {
            text: sameSideIndex !== index ? '' : `${item.Unit}`,
            // text: null,
            align: 'high',
            rotation: 0,
            y: -15,
            offset: 0
          },
          opposite: [0,2].includes(item.IsAxis),
          reversed: item.IsOrder,
          min: Number(chartData[sameSideIndex].MinData),
          max: Number(chartData[sameSideIndex].MaxData),
          tickWidth: sameSideIndex !== index ? 0 : 1,
        }

        // //拼接标题 判断相同指标名称拼接来源
        let dynamic_title = item.EdbName;
        let dynamic_arr = chartData.filter(
          (item: IDataProps) => dynamic_title === item.EdbName
        );

        // 拼接配置  IsAxis左轴1 右轴0 IsOrder正序false 逆序true EdbInfoType是否是领先指标
        let dynamic_tag = concatDynamicTag(item)

        //数据列
        let obj = {
          data: [] as any[],
          type:  'spline',
          yAxis: sameSideIndex,
          name:
            dynamic_arr.length > 1
              ? `${item.EdbName}(${item.SourceName})${dynamic_tag}`
              : `${item.EdbName}${dynamic_tag}`,
          color: item.ChartColor,
          lineWidth: Number(item.ChartWidth)
        };
        item.DataList = item.DataList || []
        for (let i of item.DataList) {
          obj.data.push([i.DataTimestamp, i.Value]);
        }

        if(item.DataList.length){
            minTimeArr.push(item.DataList[0].DataTimestamp)
            maxTimeArr.push(item.DataList[item.DataList.length-1].DataTimestamp)
        }

        data.push(obj);
        ydata.push(yItem);
      })

      // 范围为1年内 x轴显示为月/日 否则默认年/月
      let xAxis:any = {};
      const bool_time:boolean = xTimeDiffer();
      let minTime: number=Math.min(...minTimeArr);
      let maxTime=Math.max(...maxTimeArr);

      let step = setXaxisStep(maxTime-minTime);

      xAxis = bool_time ? {
        ...defaultOpts.xAxis,
        tickInterval: screen.value === 'phone' ? step : undefined,
        labels: {
          formatter: function (ctx: any) {
            return Highcharts.dateFormat('%m/%d', ctx.value);
          },
          style: {
            fontSize: '10px',
          },
        }
      } : {
        ...defaultOpts.xAxis,
        tickInterval: screen.value === 'phone' ? step : undefined,
        labels: {
          style: {
            fontSize: '10px',
          },
        },
      }

      state.options = {
        series: data,
        yAxis: ydata,
        xAxis
      };
    }

    /* 设置x轴步长 刻度数量多一点 */
    const setXaxisStep = (timestamp: number) => {
      // return  timestamp / 6 < 24 * 3600 * 1000 * 30 ? 24 * 3600 * 1000 * 30 : timestamp / 6;
      return  timestamp / 6;
    }

    /* 指标顺序调整  IsAxis: 0右轴 1左轴 2右2*/
    const changeEdbOrder = (data: any[]) => {
      // 左轴指标
      let left_edbs = data.filter(_ => _.IsAxis===1);
      //右轴指标
      let right_edbs = data.filter(_ => !_.IsAxis);
      // 右2轴指标
      let right_two_edbs = data.filter(_ => _.IsAxis === 2);
      // 按 左 右 右2顺序排列
      return [left_edbs,right_edbs,right_two_edbs].flat(Infinity);
    }

    /* 堆叠图/组合图设置  
    本来和曲线图逻辑基本一致兼容下即可 为了以后便于维护和阅读还是拆开写吧
     */
    const setStackOrCombinChart = () => {
      const { dataList,chartInfo } = state;

      //拼接标题 数据列
      let data = [] as any[],ydata = [] as any[],minTimeArr: number[] = [],maxTimeArr: number[] = [];
      // const chartData = _.cloneDeep(dataList);
      //有右二轴时排个序 按照左 右 右2的顺序
      let chartData = dataList.some(_ =>_.IsAxis===2) ? changeEdbOrder(dataList) : _.cloneDeep(dataList);

      //支持的图表类型
      const chartTypeMap: IChartType  = {
        3: 'areaspline',
        4: 'column',
        6: ''
      };
      let chartStyle = chartTypeMap[chartInfo.ChartType];
      
      chartData.forEach((item:IDataProps ,index:number) => {

        //轴位置值相同的下标
        let sameSideIndex = chartData.findIndex(
          (i:IDataProps) => i.IsAxis === item.IsAxis
        );
        
         //堆叠图的yAxis必须一致 数据列所对应的y轴
        let serie_yIndex = index;
        if([3,4].includes(chartInfo.ChartType)) {
          // 类型为堆叠图时公用第一个指标y轴 
          serie_yIndex =  0;
        } else if(chartInfo.ChartType ===6 && ['areaspline','column'].includes(item.ChartStyle)) {
          // 组合图找第一个堆叠柱状或面积的作为公用
          serie_yIndex = chartData.findIndex((i:IDataProps) => i.ChartStyle === item.ChartStyle);
        }
        //数据对应的y轴是公用轴则配置也共享
        item.IsAxis = serie_yIndex === index ? item.IsAxis : chartData[serie_yIndex].IsAxis;
        item.IsOrder = serie_yIndex === index ? item.IsOrder : chartData[serie_yIndex].IsOrder;

        //y轴
        let yItem = {
          ...basicYAxis,
          labels: {
            formatter: function (ctx: any) {
              let val =  Math.abs(ctx.value) < 1000 ? ctx.value :  ctx.value / 1000 + 'k';
              return sameSideIndex !== index ? '' : val;
            },
            align: 'center',
            x: [0,2].includes(item.IsAxis) ? 5 : -5,
            style: {
              fontSize: '10px',
            },
          },
          title: {
            text: sameSideIndex !== index ? '' : `${item.Unit}`,
            // text: null,
            align: 'high',
            rotation: 0,
            y: -15,
            offset: 0
          },
          opposite: [0,2].includes(item.IsAxis),
          reversed: item.IsOrder,
          min: Number(chartData[sameSideIndex].MinData),
          max: Number(chartData[sameSideIndex].MaxData),
          tickWidth: sameSideIndex !== index ? 0 : 1,
          visible: serie_yIndex === index ? true : false
        }

        // //拼接标题 判断相同指标名称拼接来源
        let dynamic_title = item.EdbName;
        let dynamic_arr = chartData.filter(
          (item: IDataProps) => dynamic_title === item.EdbName
        );

        // 拼接配置  IsAxis左轴1 右轴0 IsOrder正序false 逆序true EdbInfoType是否是领先指标
        let dynamic_tag = concatDynamicTag(item)

        //数据列
        let obj = {
          data: [] as any[],
          type: chartStyle || item.ChartStyle,
          yAxis: serie_yIndex,
          name:
            dynamic_arr.length > 1
              ? `${item.EdbName}(${item.SourceName})${dynamic_tag}`
              : `${item.EdbName}${dynamic_tag}`,
          color: item.ChartColor,
          lineWidth: (chartInfo.ChartType === 6 && item.ChartStyle === 'spline') ? Number(item.ChartWidth) : 0,
          fillColor: (chartInfo.ChartType === 3 || (chartInfo.ChartType === 6 && item.ChartStyle === 'areaspline')) ? item.ChartColor : undefined,
          zIndex: (chartInfo.ChartType === 6 && item.ChartStyle === 'spline') ? 1 : 0 //防止组合图曲线被遮住
          
        };
        item.DataList = item.DataList || []
        for (let i of item.DataList) {
          obj.data.push([i.DataTimestamp, i.Value]);
        }

        if(item.DataList.length){
            minTimeArr.push(item.DataList[0].DataTimestamp)
            maxTimeArr.push(item.DataList[item.DataList.length-1].DataTimestamp)
        }

        data.push(obj);
        ydata.push(yItem);
      })

      // 范围为1年内 x轴显示为月/日 否则默认年/月
      let xAxis:any = {};
      const bool_time:boolean = xTimeDiffer();
      let minTime: number=Math.min(...minTimeArr);
      let maxTime=Math.max(...maxTimeArr);

      let step = setXaxisStep(maxTime-minTime);

      xAxis = bool_time ? {
        ...defaultOpts.xAxis,
        tickInterval: screen.value === 'phone' ? step : undefined,
        labels: {
          formatter: function (ctx: any) {
            return Highcharts.dateFormat('%m/%d', ctx.value);
          },
          style: {
            fontSize: '10px',
          },
        }
      } : {
        ...defaultOpts.xAxis,
        tickInterval: screen.value === 'phone' ? step : undefined,
        labels: {
          style: {
            fontSize: '10px',
          },
        },
      }

      state.options = {
        series: data,
        yAxis: ydata,
        xAxis
      };
    }

    /* 季节图 */
    const setSeasonOptions = () => {
      const chartData = state.dataList[0];
      let seasonYdata = [],
        seasonData = [],
        chart = {
          spacing: [5, 8, 2, 8],
        };

      /* 公历数据处理 处理数据列 y轴 */
      if (state.chartInfo.Calendar === '公历')
        for (let j of chartData.DataList) {
          let serie_item = {
            data: [] as any[],
            type: chartData.ChartStyle,
            yAxis: 0,
            name: j.Year,
          };
          const data_array = _.cloneDeep(j.DataList);
          data_array &&
            data_array.forEach((item: IParams) => {
              serie_item.data.push([item.DataTimestamp, item.Value]);
            });
          const index = chartData.DataList.findIndex(
            (item: ISeasonDataItemProps) => item.Year === j.Year
          );
          const s_yItem = {
            labels: {
              formatter: function (ctx: any) {
                let val = ctx.value < 1000 ? ctx.value :  ctx.value / 1000 + 'k';
                return index !== 0 ? '' : val;
              },
              align: 'center',
              style: {
                fontSize: '10px',
              },
              x: -5,
            },
            title: {
              text:  `${chartData.Unit}`,
              // text: null,
              align: 'high',
              rotation: 0,
              y: -15,
              offset: -(10 * chartData.Unit.length),
            },
            max: Number(chartData.MaxData),
            min: Number(chartData.MinData),
            ...defaultOpts.yAxis,
          };
          seasonData.push(serie_item);
          seasonYdata.push(s_yItem);
        }

      /* 农历数据处理  */
      let filterArr =
        state.chartInfo.Calendar === '农历'
          ? chartData.DataList.List.filter(
              (item: ILunarItem, index: number) => index > 0
            )
          : [];
      if (state.chartInfo.Calendar === '农历')
        for (let j of filterArr) {
          let serie_item = {
            data: [] as any[],
            type: chartData.ChartStyle,
            yAxis: 0,
            name: j.Year,
          };
          const data_array = _.cloneDeep(j.Items);
          data_array &&
            data_array.forEach((item: IParams) => {
              serie_item.data.push([item.DataTimestamp, item.Value]);
            });
          const index = filterArr.findIndex(
            (item: ILunarItem) => item.Year === j.Year
          );

          const s_yItem = {
            labels: {
              formatter: function (ctx: any) {
                let val = ctx.value < 1000 ? ctx.value : ctx.value / 1000 + 'k';
                return index !== 0 ? '' : val;
              },
              align: 'center',
              style: {
                fontSize: '10px',
              },
              x: -5,
            },
            title: {
              text:  `${chartData.Unit}`,
              // text: null,
              align: 'high',
              rotation: 0,
              y: -15,
              offset: -(10 * chartData.Unit.length),
            },
            max: Number(chartData.MaxData),
            min: Number(chartData.MinData),
            ...defaultOpts.yAxis,
          };
          seasonData.push(serie_item);
          seasonYdata.push(s_yItem);
        }

      // 季节图x轴显示月/日 周度指标额外处理时间轴显示
      const xAxis = {
        ...defaultOpts.xAxis,
        tickInterval:  screen.value === 'phone' ? 24 * 3600 * 1000 * 60 : undefined,
        labels: {
          formatter: function (ctx: any) {
            return Highcharts.dateFormat('%m/%d', ctx.value);
          },
          style: {
            fontSize: '10px',
          },
        },
      };

      // 季节图提示框显示 月/日
      defaultOpts.tooltip = {
        split: false,
        shared: true,
        dateTimeLabelFormats: {
          // 时间格式化字符
          day: '%m/%d',
          week: '%m/%d',
          month: '%m/%d',
          year: '%m/%d',
        },
        xDateFormat: '%m/%d',
        // valueDecimals: 2,
      };

      //农历默认选中一年数据并隐藏按钮  公历显示全部数据
      let rangeSelector = state.chartInfo.Calendar === '农历'
        ? {
            enabled: true,
            selected: 0,
            inputStyle: {
              display: 'none',
            },
            labelStyle: {
              display: 'none',
            },
            buttonTheme: {
              style: {
                display: 'none',
              },
            },
            buttons: [
              {
                type: 'month',
                count: 12,
                text: '12月',
              },
              {
                type: 'month',
                count: 15,
                text: '15月',
              },
              {
                type: 'all',
                text: '全部',
              },
            ],
          }
        : {
            enabled: false,
          };

      state.options = {
        colors:
          state.chartInfo.Calendar === '公历'
            ? seasonOptions.colors.slice(-chartData.DataList.length)
            : seasonOptions.colors.slice(-filterArr.length),
        series: seasonData,
        yAxis: seasonYdata,
        xAxis,
        rangeSelector,
        chart
      };
    }

    /* 散点图 第一个指标值为x轴 第二个指标为y轴*/
    const setScatterChartOptions = () => {
      const { dataList,chartInfo } = state;

      // 取2个指标中日期相同的数据
      const real_data: any[] = [];
      let tmpData_date: any = {};//用来取点对应的日期
      let data1 =  _.cloneDeep(dataList)[0].DataList || [];
      let data2 =  _.cloneDeep(dataList)[1].DataList || [];
      data1.forEach((_item: IParams) => {
        data2.forEach((_item2: IParams) => {
          if(_item.DataTimestamp === _item2.DataTimestamp) {
            //日期
            let itemIndex =_item.Value + "_" +_item2.Value
            if(tmpData_date[itemIndex]) {
              tmpData_date[itemIndex].push( moment(_item.DataTimestamp).format('YYYY/MM/DD'))
            } else {
              tmpData_date[itemIndex] = [moment(_item.DataTimestamp).format('YYYY/MM/DD')]
            }
            
            //值
            real_data.push({
              x: _item.Value,
              y: _item2.Value
            })
          }
        })
      })
      real_data.sort((x,y) => x-y);

      //悬浮窗 拼接日期 原始指标名称
      let tooltip = {
        formatter: function() {
          const that: any = this;
          return `<strong>${ tmpData_date[that.x+'_'+that.y].length > 4 ? tmpData_date[that.x+'_'+that.y].slice(0,4).join()+'...' : tmpData_date[that.x+'_'+that.y].join() }</strong><br>
          ${dataList[0].EdbName}: <span style="font-weight: 600">	${that.x}</span><br>
          ${dataList[1].EdbName}: <span style="font-weight: 600">	${that.y}</span>
          `
        }
      }

      const { IsOrder,ChartColor } = dataList[0];
      //y轴
      let yAxis = {
        title: {
          text:  `${dataList[1].Unit}`,
          // text: null,
          align: 'high',
          rotation: 0,
          y: -5,
          offset: -(10 * dataList[1].Unit.length),
        },
        labels: {
          formatter: function (ctx: any) {
            return ctx.value;
          },
          align: 'center',
        },
        opposite: false,
        reversed: IsOrder,
        min: Number(dataList[0].MinData),
        max: Number(dataList[0].MaxData),
        tickWidth: 1,
        tickLength: 5,
        lineWidth: 1,
        lineColor: '#bfbfbf',
        tickColor: '#bfbfbf',
        offset: 0,
        visible: true,
        gridLineWidth: 0,
        tickPosition: 'inside',
        endOnTick: false,
        startOnTick: false,
        showLastLabel: true,
        tickPixelInterval: 50
      }

      //数据列
      let series: any = {
        data: [],
        type: 'scatter',
        name: `${chartInfo.ChartName}${IsOrder ? '(逆序)' : ''}`,
        color: ChartColor,
        lineWidth: 0
      }
      real_data.forEach(_ => {
        series.data.push([_.x,_.y])
      })
      
      state.options = {
        title: {
          text:''
        },
        series: [ series ],
        yAxis,
        xAxis: {
          ...scatterXAxis,
          title: {
            text:  `${dataList[0].Unit}`,
            // text: null,
            align: 'high',
            rotation: 0,
            x: 0,
            offset: 20,
          },
        },
        tooltip
      }
      console.log(state.options)
    }

    /* 设置options */
    const setOptions = () => {
      // ChartType: 1曲线图 2季节图 3面积图 4柱状图 5散点图 6组合图  季节图中公历和农历数据结构不同
      const { chartInfo } = state;
      const chartSetMap: any = {
        1: setDefaultLineOptions,
        2: setSeasonOptions,
        3: setStackOrCombinChart,
        4: setStackOrCombinChart,
        5: setScatterChartOptions,
        6: setStackOrCombinChart
      };

      chartSetMap[chartInfo.ChartType]()
    };

    /* 拼接动态的指标名称小标签 */
    const concatDynamicTag = ({ IsAxis,IsOrder,EdbInfoType,LeadValue,LeadUnit }: IDataProps ): string => {
      // IsAxis左轴1 右轴0 2右2轴 
      //IsOrder正序false 逆序true 
      //EdbInfoType是否是领先指标
      const axisLabelMap:any = {
        0: '右轴',
        2: '右2轴'
      }
      const orderLabelMap:any = {
        1: '逆序'
      }
      const edbInfoMap:any = {
        0: '领先'
      }
      
      let axis_tag = axisLabelMap[IsAxis] || '';
      //逆序拼接
      let order_tag = orderLabelMap[Number(IsOrder)] ? `${axis_tag ? '，': ''}${orderLabelMap[Number(IsOrder)]}` : ''
      //领先拼接
      let edb_tag = edbInfoMap[EdbInfoType] ? `${(axis_tag||order_tag) ? '，' : '' }${edbInfoMap[EdbInfoType]}${LeadValue}${LeadUnit}` : '';

      return (axis_tag || order_tag || edb_tag) ? `(${axis_tag}${order_tag}${edb_tag})` : ''
    }

    /* 分享链接 */
    const copyUrl = () => {
      let input = document.createElement("input");
      input.value = location.href;
      document.body.appendChild(input)
      input.select();
      document.execCommand('copy');
      document.body.removeChild(input);
      ElMessage.success('复制链接成功')
    }

    const refreshChart = _.debounce(async () => {
      loading.value = true;
      let { Ret } = await ChartApi.refreshChart({ UniqueCode: state.chartInfo.UniqueCode });
      Ret === 200 && getChartInfo('refresh');
    },400)

    return {
      ...toRefs(state),
      loading,
      haveData,
      getChartInfo,
      openNew,
      copyUrl,
      isShare,
      refreshChart,
    };
  },
});
</script>
<style scoped lang="less">
@import './index.less';
</style>
