import { inject, nextTick, reactive, toRefs, watch } from 'vue';

import { useGo } from '@jnpf/hooks';
import { encryptByBase64 } from '@jnpf/utils';

import { useEcharts } from '@vben/plugins/echarts';

import * as echarts from 'echarts';
import { cloneDeep } from 'lodash-es';

import { getDataInterfaceRes } from '#/api/systemData/dataInterface';
import { getParamList } from '#/utils/jnpf';

import CardHeader from '../../Portal/CardHeader/index.vue';
import { chartData as defaultChartData } from '../helper/dataMap';

export function useEChart(activeData, chartRef) {
  interface State {
    currOption: any;
    chartData: any[];
  }
  const state = reactive<State>({
    currOption: {},
    chartData: [],
  });
  const { chartData, currOption } = toRefs(state);
  const { renderEcharts, resize } = useEcharts(chartRef, handleClick);
  const emitter: any = inject('emitter');
  const go = useGo();

  watch(
    () => activeData.option,
    () => {
      initChartData();
    },
    { deep: true },
  );
  watch(
    () => activeData.dataType,
    (val) => {
      activeData.option.defaultValue = [];
      state.chartData = [];
      if (val == 'static') initStaticData(activeData.option.styleType);
      initBarType();
    },
    { deep: true },
  );
  watch(
    () => activeData.option.styleType,
    (val) => {
      if (activeData.dataType == 'static') initStaticData(val);
      initBarType();
    },
  );
  watch(
    () => activeData.option.defaultValue,
    (val) => {
      if (activeData.dataType !== 'static') return;
      setTimeout(() => {
        state.chartData = val;
        initChartData();
        initBarType();
      }, 0);
    },
  );
  watch(
    () => activeData.propsApi,
    (val) => {
      if (activeData.dataType === 'static' || !val) return;
      const query = { paramList: getParamList(activeData.templateJson) };
      getDataInterfaceRes(val, query).then((res) => {
        state.chartData = res.data;
        initChartData();
        initBarType();
      });
    },
  );
  watch(
    () => activeData.mappingConfig,
    () => {
      initChartData();
    },
    { deep: true },
  );

  function init() {
    if (activeData.dataType === 'dynamic') {
      if (!activeData.propsApi) return (state.chartData = []);
      const query = { paramList: getParamList(activeData.templateJson) };
      getDataInterfaceRes(activeData.propsApi, query).then((res) => {
        state.chartData = res.data;
        initChartData();
      });
    } else {
      setTimeout(() => {
        state.chartData = activeData.option.defaultValue;
        initChartData();
      }, 0);
    }
    emitter.on(`eChart${activeData.i}`, () => {
      nextTick(() => resize());
    });
  }
  function mappingConfig() {
    const optionData = cloneDeep(state.chartData) || [];
    if (!activeData.mappingConfig || activeData.dataType === 'static') return optionData;
    if (['barChart', 'lineChart', 'pieChart'].includes(activeData.jnpfKey))
      return optionData.map((o) => ({
        type: o[activeData.mappingConfig[0].value ? activeData.mappingConfig[0].value : 'type'],
        name: o[activeData.mappingConfig[1].value ? activeData.mappingConfig[1].value : 'name'],
        value: o[activeData.mappingConfig[2].value ? activeData.mappingConfig[2].value : 'value'],
      }));
    if (activeData.jnpfKey == 'radarChart')
      return optionData.map((o) => ({
        type: o[activeData.mappingConfig[0].value ? activeData.mappingConfig[0].value : 'type'],
        name: o[activeData.mappingConfig[1].value ? activeData.mappingConfig[1].value : 'name'],
        value: o[activeData.mappingConfig[2].value ? activeData.mappingConfig[2].value : 'value'],
        max: o[activeData.mappingConfig[3].value ? activeData.mappingConfig[3].value : 'max'],
      }));
  }
  function initChartData() {
    const jnpfKey = activeData.jnpfKey;
    const styleType = activeData.option.styleType;
    const option = activeData.option;
    const optionData = mappingConfig();
    const typeArr = [...new Set(optionData.map((item) => item.type))];
    const axisData = [...new Set(optionData.map((item) => item.name))];
    const seriesData: any[] = [];
    typeArr.forEach((title, index) => {
      const type = getType(title);
      const obj: any = {
        name: title,
        type,
        stack: styleType == 5 || styleType == 6 || styleType == 7 || (styleType != 4 && jnpfKey == 'lineChart') ? title : 'total',
      };
      const chartArr = optionData.filter((item) => title === item.type);
      if (jnpfKey == 'pieChart') {
        obj.data = chartArr.map((item) => {
          return {
            value: item.value,
            name: item.name,
          };
        });
        if (option.sortable) getPieData(obj.data);
        if (option.showZero) obj.data = obj.data.filter((item) => item.value != 0);
      } else if (jnpfKey == 'radarChart') {
        const typeList = chartArr.map((item) => item.type);
        const element = {
          value: chartArr.map((item) => item.value),
          name: typeList && typeList.length ? typeList[0] : '',
          areaStyle: {
            color: getColor(index),
            opacity: option.seriesAreaStyleOpacity,
          },
        };
        obj.data = [element];
        obj.colorBy = 'series';
      } else {
        obj.data = chartArr.map((item) => item.value);
      }
      seriesData.push(obj);
    });
    const xAxis: any = {
      type: option.category == 'category' ? 'category' : 'value',
      show: option.xAxisShow,
      inverse: option.xAxisInverse,
      data: axisData,
      name: option.xAxisName,
      nameTextStyle: {
        color: option.xAxisNameTextStyleColor,
        fontSize: option.xAxisNameTextStyleFontSize,
        fontWeight: option.xAxisNameTextStyleFontWeight ? 'bolder' : '',
      },
      splitLine: {
        show: option.xAxisSplitLineShow,
        lineStyle: {
          color: option.xAxisSplitLineLineStyleColor,
        },
      },
      axisLabel: {
        rotate: option.xAxisAxisLabelRotate,
        color: option.AxisTextStyleColor ? option.AxisTextStyleColor : option.xAxisAxisLabelTextStyleColor,
        fontSize: option.xAxisAxisLabelTextStyleFontSize,
        fontWeight: option.xAxisAxisLabelTextFontWeight ? 'bolder' : '',
      },
      axisLine: {
        show: option.xAxisShow,
        lineStyle: {
          color: option.AxisLineStyleColor ? option.AxisLineStyleColor : option.xAxisAxisLineLineStyleColor,
        },
      },
    };
    const yAxis = [
      {
        type: option.category == 'category' ? 'value' : 'category',
        show: option.yAxisShow,
        inverse: option.yAxisInverse,
        data: axisData,
        name: option.yAxisName,
        nameTextStyle: {
          color: option.yAxisNameTextStyleColor,
          fontSize: option.yAxisNameTextStyleFontSize,
          fontWeight: option.yAxisNameTextStyleFontWeight ? 'bolder' : '',
        },
        splitLine: {
          show: option.yAxisSplitLineShow,
          lineStyle: {
            color: option.yAxisSplitLineLineStyleColor,
          },
        },
        axisLabel: {
          interval: option.yAxisAxisLabelInterval,
          rotate: option.yAxisAxisLabelRotate,
          color: option.AxisTextStyleColor ? option.AxisTextStyleColor : option.yAxisAxisLabelTextStyleColor,
          fontSize: option.yAxisAxisLabelTextStyleFontSize,
          fontWeight: option.yAxisAxisLabelTextFontWeight ? 'bolder' : '',
        },
        axisLine: {
          show: option.yAxisShow,
          lineStyle: {
            color: option.AxisLineStyleColor ? option.AxisLineStyleColor : option.yAxisAxisLineLineStyleColor,
          },
        },
      },
    ];
    const newOption: any = {
      // 标题
      title: {
        show: option.titleText || option.titleSubtext,
        text: option.titleText,
        textStyle: {
          color: option.titleTextStyleColor,
          fontSize: option.titleTextStyleFontSize,
          fontWeight: option.titleTextStyleFontWeight ? 'bolder' : '',
        },
        subtext: option.titleSubtext,
        subtextStyle: {
          color: option.titleSubtextStyleColor,
          fontSize: option.titleSubtextStyleFontSize,
          fontWeight: option.titleSubtextStyleFontWeight ? 'bolder' : '',
        },
        left: option.titleLeft,
        backgroundColor: option.titleText || option.titleSubtext ? option.titleBgColor || '#fff' : '#fff',
      },
      // 提示
      tooltip: {
        show: option.tooltipShow,
        backgroundColor: option.tooltipBgColor,
        textStyle: {
          color: option.tooltipTextStyleColor,
          fontSize: option.tooltipTextStyleFontSize,
          fontWeight: option.tooltipTextStyleFontWeight ? 'bolder' : '',
        },
      },
      // 网格
      grid: {
        left: option.gridLeft,
        top: option.gridTop,
        right: option.gridRight,
        bottom: option.gridBottom,
        containLabel: true,
      },
      // 图例
      legend: {
        show: option.legendShow,
        orient: option.legendOrient,
        textStyle: {
          fontSize: option.legendTextStyleFontSize || 12,
        },
        top: `${option.legendTop}%`,
        right: `${option.legendLeft}%`,
      },
      series: (() => {
        const list: any[] = (seriesData || []).map((ele: any, index) => {
          const label: any = {
            show: option.seriesLabelShow,
            position: jnpfKey == 'pieChart' ? option.seriesLabelPosition : 'top',
            fontSize: option.seriesLabelFontSize,
            fontWeight: option.seriesLabelFontWeight ? 'bolder' : 'normal',
            color: option.seriesLabelColor,
            backgroundColor: option.seriesLabelBgColor,
          };
          const itemStyle: any = {
            borderRadius: option.seriesItemStyleBarBorderRadius,
          };
          if (jnpfKey == 'barChart' || jnpfKey == 'lineChart' || jnpfKey == 'radarChart') itemStyle.color = getColor(index);
          if (jnpfKey == 'lineChart') {
            ele.smooth = styleType == 2;
            ele.step = styleType == 3;
            ele.lineStyle = {
              width: option.seriesLineStyleWidth,
            };
            ele.symbolSize = option.seriesSymbolRotate;
            if (option.areaStyle) ele.areaStyle = {};
          }
          if (jnpfKey == 'pieChart') {
            if (styleType == 1) ele.radius = '60%';
            if (styleType == 2) ele.radius = ['30%', '60%'];
            if (option.roseType) ele.roseType = 'area';
            if (option.seriesLabelShowInfo && option.seriesLabelShowInfo.length) {
              if (option.seriesLabelShowInfo.includes('count') && option.seriesLabelShowInfo.includes('percent')) {
                label.formatter = '{b}: {c} ({d}%)';
              } else if (option.seriesLabelShowInfo.includes('count')) {
                label.formatter = '{b}: {c} ';
              } else if (option.seriesLabelShowInfo.includes('percent')) {
                label.formatter = '{b}: ({d}%) ';
              }
            }
            if (option.colorList && option.colorList.length) {
              const colorList: any[] = [];
              option.colorList.map((_item, index) => {
                const color = getColor(index) || '#71B6F5';
                colorList.push(color);
                return _item;
              });
              ele.color = colorList;
            }
            ele.center = [`${option.seriesCenterLeft}%`, `${option.seriesCenterTop}%`];
          }
          return Object.assign(ele, {
            name: ele.name,
            type: ele.type,
            data: ele.data,
            stack: ele.stack,
            showBackground: styleType == 4,
            barWidth: option.seriesBarWidth,
            itemStyle,
            label,
          });
        });
        return list;
      })(),
    };
    if (jnpfKey == 'barChart' || jnpfKey == 'lineChart') {
      if (jnpfKey == 'lineChart' && option.areaStyle) xAxis.boundaryGap = false;
      newOption.xAxis = xAxis;
      newOption.yAxis = yAxis;
    } else if (jnpfKey == 'radarChart') {
      newOption.radar = [];
      typeArr.map((item) => {
        const indicator = axisData.map((items) => {
          const maxObj = optionData.find((element) => {
            return element.type == item && element.name == items;
          });
          return {
            name: items,
            max: maxObj ? maxObj.max : '',
          };
        });
        const radarObj = {
          indicator,
          shape: option.styleType == 1 ? 'polygon' : 'circle',
          axisName: {
            fontSize: option.radarAxisNameFontSize,
            fontWeight: option.radarAxisNameFontWeight ? 'bolder' : 'normal',
            color: option.radarAxisNameColor,
          },
          center: [`${option.radarCenterLeft}%`, `${option.radarCenterTop}%`],
        };
        newOption.radar.push(radarObj);
        return item;
      });
    } else if (jnpfKey == 'pieChart') {
      if (option.seriesLabelShowInfo.includes('count') && option.seriesLabelShowInfo.includes('percent')) {
        newOption.tooltip.formatter = '{b}: {c} ({d}%)';
      } else if (option.seriesLabelShowInfo.includes('count')) {
        newOption.tooltip.formatter = '{b}: {c}';
      } else if (option.seriesLabelShowInfo.includes('percent')) {
        newOption.tooltip.formatter = '{b}: {d}%';
      } else {
        newOption.tooltip.formatter = '{b}';
      }
    }
    state.currOption = newOption;
    renderEcharts(newOption, true);
  }
  function getType(title) {
    const jnpfKey = activeData.jnpfKey;
    const option = activeData.option;
    if (jnpfKey == 'barChart') {
      if (option.styleType == 7) {
        const arr = option.barType.find((ele) => title == ele.title);
        if (arr && arr.type) return arr.type;
      }
      return 'bar';
    } else if (jnpfKey == 'lineChart') {
      return 'line';
    } else if (jnpfKey == 'pieChart') {
      return 'pie';
    } else if (jnpfKey == 'radarChart') {
      return 'radar';
    }
  }
  function getColor(index) {
    const option = activeData.option;
    const barColor = option.colorList || [];
    if (barColor[index]) {
      const color1 = barColor[index].color1;
      const color2 = barColor[index].color2;
      if (color2 && color1)
        return new echarts.graphic.LinearGradient(0, 0, 0, 1, [
          { offset: 0, color: color1 },
          { offset: 1, color: color2 },
        ]);
      return color1;
    }
  }
  function getPieData(list) {
    for (let i = 0; i < list.length - 1; i++) {
      for (let j = 0; j < list.length - 1; j++) {
        if (list[j].value > list[j + 1].value) {
          const t = list[j];
          list[j] = list[j + 1];
          list[j + 1] = t;
        }
      }
    }
  }
  function initStaticData(val) {
    const jnpfKey = activeData.jnpfKey;
    activeData.option.defaultValue = [];
    if (jnpfKey == 'barChart') {
      if (val == 1 || val == 4) activeData.option.defaultValue = defaultChartData.baseBarData;
      if (val == 2 || val == 5) activeData.option.defaultValue = defaultChartData.mulBarData;
      if (val == 6) activeData.option.defaultValue = defaultChartData.plusMinusBarData;
      if (val == 7) {
        activeData.option.defaultValue = defaultChartData.brokenColumnBarData;
        initBarType();
      }
    } else if (jnpfKey == 'lineChart') {
      if (val == 1 || val == 2 || val == 3) activeData.option.defaultValue = defaultChartData.baseBarData;
      if (val == 4) activeData.option.defaultValue = defaultChartData.mulBarData;
    } else if (jnpfKey == 'pieChart') {
      activeData.option.defaultValue = defaultChartData.baseBarData;
    } else if (jnpfKey == 'radarChart') {
      activeData.option.defaultValue = defaultChartData.radarData;
    }
  }
  function initBarType() {
    const option = activeData.option;
    if (option.styleType !== 7) return;
    const optionData = state.chartData || [];
    if (!Array.isArray(optionData)) return;
    option.barType = [];
    const typeArr = [...new Set(optionData.map((item) => item.type))];
    typeArr.map((item, index) => {
      if (item) {
        option.barType.push({
          title: item,
          type: index == 1 ? 'line' : 'bar',
        });
      }
      return item;
    });
  }
  function handleClick(item) {
    if (!activeData.option?.urlAddress) return;
    let urlAddress = cloneDeep(activeData.option.urlAddress);
    const regex = /\$\{[^{}]+\}/g;
    urlAddress = urlAddress.replaceAll(regex, (match) => {
      const key = match.slice(2, -1);
      let value = '';
      if (key === 'type') value = item.seriesName;
      if (key === 'name') value = item.name;
      if (key === 'value') value = item.value;
      return value || match;
    });
    if (activeData.option.target == '_self') {
      go(`/externalLink?href=${encodeURIComponent(encryptByBase64(urlAddress))}`);
    } else {
      window.open(urlAddress, activeData.option.target);
    }
  }

  return {
    CardHeader,
    chartData,
    currOption,
    init,
  };
}
