<template>
  <div ref="chartWrap" :class="['dc-chart', simple ? 'simple-chart' : '']">
    <div v-if="chartTitle" class="dc-chart-title">{{ chartTitle }}</div>
    <div class="dc-chart-content">
      <Loading :visible="loading"></Loading>
      <template v-if="data && data.rows && data.rows.length">
        <ChartToolbar v-if="showToolbar" :class="{ editable: showEdit }">
          <template #left>
            <template v-if="simple">
              <!-- 切换指标组件 -->
              <div v-for="(index, i) in indexValue" :key="i" class="index-select">
                <Select :value="indexValue[i]" @on-change="handleIndexChange($event, i)">
                  <template v-if="!isMultiDimension" #prefix>
                    <div class="index-color-bar" :style="{ borderColor: indexColors[i] }"></div>
                  </template>
                  <Option
                    v-for="item in indexOptionArr[i]"
                    :disabled="item.disabled"
                    :key="item.value"
                    :value="item.value"
                  >
                    {{ item.label }}
                  </Option>
                </Select>
              </div>
            </template>
            <template v-else-if="dimensionValue.length && dimensionValue[0] !== 'total'">
              <!-- 维度过滤组件 -->
              <ChartDimensionFilter
                v-for="item in dimensionFilterData"
                v-model="item.value"
                :key="item.key"
                :label="item.label"
                :options="item.options"
                @on-dimension-change="handleChartDimensionChange"
              ></ChartDimensionFilter>
            </template>
          </template>
          <template #right>
            <template v-if="simple">
              <!-- 切换维度组件 -->
              <Select
                v-show="isDimensionEnabled"
                class="dimension-select"
                :value="dimensionValue[0]"
                @on-change="handleDimensionChange"
              >
                <Option v-for="item in dimensionList" :key="item.value" :value="item.value">
                  {{ item.label }}
                </Option>
              </Select>
            </template>
            <template v-else>
              <!-- 图表类型切换组件 -->
              <ChartTypeRadioGroup
                v-if="showTypeToggle"
                v-model="chartType"
                :no-pie="!isMultiDimension"
                :no-dual-axis="!isMultiIndex || isMultiDimension"
                @on-change="handleChartTypeChange"
              ></ChartTypeRadioGroup>
            </template>
            <FullscreenIcon v-if="fullscreen" @on-click="handleFullscreen"></FullscreenIcon>
          </template>
        </ChartToolbar>
        <SimpleChartLegend
          v-if="simple && isMultiDimension"
          :data="simpleLegendData"
          :chart-element="chartElement"
        ></SimpleChartLegend>
        <BaseChart
          ref="baseChart"
          :option="chartOption"
          :height="simple && isMultiDimension ? height - 20 : height"
        ></BaseChart>
        <ChartLegend
          v-if="showLegend && !simple"
          :data="legendData"
          :chart-element="chartElement"
          :chart-type="chartType"
        ></ChartLegend>
      </template>
      <template v-else>
        <EmptyContent v-if="!loading" :empty_text="emptyText"></EmptyContent>
      </template>
      <ChartOperation
        :simple="simple"
        v-if="showEdit"
        @on-edit="handleChartEdit"
        @on-delete="handleChartDelete"
      ></ChartOperation>
    </div>
  </div>
</template>

<script>
/* eslint-disable no-param-reassign,no-restricted-syntax,camelcase */
import { merge, cloneDeep } from 'lodash-es';
import Loading from '@/components/Loading.vue';
import { getInstanceByDom } from 'echarts/core';
import { colors, getLabelMapFromList, getLetterByNumber, standardizeValue } from '@/utils';
import { getGridOption, getMarkLineOption, getYAxisOption } from '@/components/base-chart/defaultOption';
import { getAxisFormatter, getTooltipFormatter } from '@/components/base-chart/formatters';
import simpleLegendMixin from '@/components/simpleLegendMixin';
import fullscreenMixin from '@/components/fullscreenMixin';
import BaseChart from './base-chart/BaseChart.vue';
import ChartOperation from './ChartOperation.vue';
import ChartTypeRadioGroup from './ChartTypeRadioGroup.vue';
import ChartDimensionFilter from './ChartDimensionFilter.vue';
import ChartToolbar from './ChartToolbar.vue';
import ChartLegend from './ChartLegend.vue';
import { getSeries } from './base-chart/seriesOptions';
import EmptyContent from './EmptyContent.vue';
import SimpleChartLegend from './SimpleChartLegend.vue';
import FullscreenIcon from './FullscreenIcon.vue';

export default {
  components: {
    Loading,
    EmptyContent,
    ChartLegend,
    ChartToolbar,
    ChartDimensionFilter,
    ChartTypeRadioGroup,
    ChartOperation,
    BaseChart,
    SimpleChartLegend,
    FullscreenIcon,
  },
  mixins: [simpleLegendMixin, fullscreenMixin],
  props: {
    type: {
      type: [String, Array],
      default: 'line',
    },
    showTitle: {
      type: Boolean,
      default: false,
    },
    title: {
      type: String,
      default: '',
    },
    height: {
      type: Number,
    },
    data: {
      type: Object,
    },
    indexValue: {
      type: Array,
      default: () => [],
    },
    indexList: {
      type: Array,
      default: () => [],
    },
    dimensionValue: {
      type: Array,
      default: () => ['total'],
    },
    dimensionList: {
      type: Array,
      default: () => [],
    },
    option: {
      type: Object,
    },
    tooltipConfig: {
      type: Object,
    },
    emptyText: {
      type: String,
      default: '暂无数据',
    },
    simple: {
      type: Boolean,
      default: false,
    },
    showToolbar: {
      type: Boolean,
      default: true,
    },
    showLegend: {
      type: Boolean,
      default: true,
    },
    loading: {
      type: Boolean,
      default: false,
    },
    showTypeToggle: {
      type: Boolean,
      default: true,
    },
    showEdit: {
      type: Boolean,
      default: false,
    },
    markData: {
      type: Array,
    },
    fullscreen: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      isMounted: false,
      chartElement: null,
      chartOption: null,
      dimensionFilterData: [],
      chartType: '',
    };
  },
  computed: {
    chartTitle() {
      if (this.title) return this.title;
      if (!this.showTitle) return '';
      let { title } = this;
      if (!title) {
        title = this.indexValue.map(x => this.indexLabelMap.get(x)).join(' 和 ');
      }
      return title;
    },
    isDimensionEnabled() {
      return !this.isMultiIndex;
    },
    indexOptionArr() {
      const arr = [];
      this.indexValue.forEach((index, i) => {
        const options = cloneDeep(this.indexList);
        options.forEach(option => {
          const excludeValues = [...this.indexValue];
          excludeValues.splice(i, 1);
          option.disabled = excludeValues.includes(option.value);
        });
        arr.push(options);
      });
      return arr;
    },
    isMultiIndex() {
      return this.indexValue.length > 1;
    },
    isMultiDimension() {
      return this.dimensionValue.length > 0 && !this.dimensionValue.includes('total');
    },
    indexColors() {
      return this.chartOption?.series.map(x => x.itemStyle?.color) ?? [];
    },
    indexLabelMap() {
      return getLabelMapFromList(this.indexList);
    },
    dimensionLabelMap() {
      return getLabelMapFromList(this.dimensionList);
    },
    legendData() {
      if (!this.chartOption) {
        return null;
      }
      const indexObj = {};
      const { series } = this.chartOption;
      if (this.chartType === 'pie') {
        const { data } = series[0];
        indexObj[0] = [];
        for (const item of data) {
          const { name, itemStyle } = item;
          const obj = {
            name,
            dimensionName: name,
            color: itemStyle.color,
            selected: true,
          };
          indexObj[0].push(obj);
        }
      } else {
        for (const item of series) {
          const { name, encode } = item;
          let indexName = '';
          let dimensionName = name;
          const curIndex = this.indexValue.find(x => name.startsWith(`${x}_`));
          if (curIndex) {
            indexName = this.indexLabelMap.get(curIndex);
            // eslint-disable-next-line prefer-destructuring
            dimensionName = name.split(`${curIndex}_`)[1];
          }
          const indexLetter = getLetterByNumber(this.indexValue.indexOf(curIndex));
          const obj = {
            name,
            dimensionName,
            color: item.itemStyle?.color,
            indexLetter,
            indexName,
            selected: true,
          };
          const seriesArr = indexObj[indexName];
          if (!seriesArr) {
            indexObj[indexName] = [obj];
          } else {
            seriesArr.push(obj);
          }
        }
      }
      return Object.entries(indexObj);
    },
  },
  created() {},
  watch: {
    type: {
      immediate: true,
      handler(val) {
        this.chartType = Array.isArray(val) ? val[0] : val;
      },
    },
    data: {
      handler(val) {
        if (val?.rows?.length) {
          this.$nextTick(() => {
            this.chartElement = this.$refs.baseChart.$refs.chart;
            if (this.simple) {
              this.setSeries();
            } else {
              this.setDimensionData();
              this.setSeries();
            }
          });
        }
      },
    },
    'tooltipConfig.markData': {
      handler(val, oldVal) {
        console.log(val, oldVal);
        if (val?.length && this.data?.rows?.length && !oldVal.length) {
          this.setSeries();
        }
      },
    },
  },
  mounted() {},
  methods: {
    setDimensionData() {
      const dimensionFilterData = [];
      this.dimensionValue.forEach((field, i) => {
        const obj = {
          key: field,
          label: this.dimensionLabelMap.get(field),
          value: [],
          options: [],
        };
        this.data.rows.forEach(row => {
          obj.options.push(this.getByValueArr(row)[i]);
        });
        obj.options = [...new Set(obj.options)];
        dimensionFilterData.push(obj);
      });
      this.dimensionFilterData = dimensionFilterData;
    },

    // 将by_values[0]统一处理成数组
    getByValueArr(row) {
      const byValue = row.by_values[0];
      if (Array.isArray(byValue)) {
        return byValue;
      }
      return [byValue];
    },

    setSeries() {
      const option = {};
      let { rows } = this.data;
      if (!this.simple) {
        // 根据选择的维度过滤数据
        const selectedDimensions = this.dimensionFilterData.map(x => x.value);
        rows = this.data.rows.filter(row => {
          let result = true;
          this.getByValueArr(row).forEach((val, i) => {
            if (!selectedDimensions[i]?.length) {
              result = result && true;
            } else {
              result = result && selectedDimensions[i].includes(val);
            }
          });
          return result;
        });
      } else {
        // simple图表多指标需要指定多个y轴
        // eslint-disable-next-line no-lonely-if
        if (this.indexValue.length > 1) {
          option.yAxis = [];
          this.indexValue.forEach((index, i) => {
            option.yAxis.push(getYAxisOption({ show: i < 2, name: this.indexLabelMap.get(index) }));
          });
          option.grid = getGridOption({ top: '32px' });
        }
      }
      const series = [];
      let dataset = [];
      if (this.chartType === 'pie') {
        option.title = [];
        const { isMultiIndex } = this;
        this.indexValue.forEach((indexName, i) => {
          const seriesData = [];
          const indexLetter = getLetterByNumber(i);
          const indexLabel = this.indexLabelMap.get(indexName);
          const leftPercent = isMultiIndex ? i * 50 + 25 : 50;
          option.title.push({
            subtext: [isMultiIndex ? `{letter|${indexLetter}}` : '', `{name| ${indexLabel}}`].join(''),
            top: 6,
            left: `${leftPercent}%`,
            textAlign: 'center',
            subtextStyle: {
              rich: {
                letter: {
                  width: 20,
                  height: 20,
                  borderRadius: 10,
                  fontSize: 10,
                  lineHeight: 20,
                  align: 'center',
                  verticalAlign: 'middle',
                  backgroundColor: '#878AA2',
                  color: '#FFFFFF',
                },
                name: {
                  fontSize: 12,
                  fontWeight: 400,
                  lineHeight: 17,
                  color: '#545778',
                },
              },
            },
          });

          rows.forEach((row, j) => {
            const seriesName = this.getByValueArr(row).join(',');
            const sumValue = row.values.reduce((total, value) => {
              return total + standardizeValue(value[i]);
            }, 0);
            seriesData.push({
              name: seriesName,
              value: sumValue,
              itemStyle: {
                color: colors[j % colors.length],
              },
            });
          });
          seriesData.sort((a, b) => b.value - a.value);
          series.push(
            getSeries(this.chartType, {
              name: indexName,
              center: [`${leftPercent}%`, '50%'],
              data: seriesData,
            })
          );
        });
        console.log(series);
      } else {
        const dimensions = ['date'];
        this.indexValue.forEach((indexName, i) => {
          rows.forEach((row, j) => {
            const seriesName = this.getByValueArr(row).join(',');
            const dimensionName = `${indexName}_${seriesName}`;
            dimensions.push(dimensionName);
            const seriesOption = {
              name: dimensionName,
              encode: { x: 'date', y: dimensionName },
              itemStyle: { color: colors[(rows.length * i + j) % colors.length] },
            };
            let seriesItem = null;

            // 多指标的简单图表使用多个不同的y轴
            if (this.simple && this.indexValue.length > 1) {
              seriesOption.yAxisIndex = i;
            }

            if (this.chartType === 'dual_axis') {
              seriesOption.yAxisIndex = i === 0 ? 1 : 0;
              seriesItem = getSeries(i === 0 ? 'bar' : 'line', seriesOption);
            } else if (Array.isArray(this.type)) {
              seriesItem = getSeries(this.type[i], seriesOption);
            } else {
              seriesItem = getSeries(this.chartType, seriesOption);
            }

            // 柱状图按指标分别进行堆叠
            if (this.chartType === 'bar') {
              if (this.indexValue.length > 1) {
                seriesItem.stack = indexName;
              } else {
                seriesItem.stack = 'bar';
              }
            }
            series.push(seriesItem);
          });
        });

        dataset = { source: [], dimensions };
        this.data.series.forEach((date, i) => {
          const arr = [date];
          this.indexValue.forEach((indexName, j) => {
            arr.push(...rows.map(x => standardizeValue(x.values?.[i]?.[j])));
          });
          dataset.source.push(arr);
        });
      }

      const tooltip = {
        trigger: this.chartType === 'pie' ? 'item' : 'axis',
        formatter: getTooltipFormatter(this.tooltipConfig),
      };
      const indexMap = new Map();
      this.indexValue.forEach((indexName, i) => {
        const indexLetter = getLetterByNumber(i);
        indexMap.set(indexName, { indexLetter, indexLabel: this.indexLabelMap.get(indexName) });
      });
      tooltip.formatter = tooltip.formatter.bind(null, indexMap);

      console.log(dataset, series);
      // 双轴线图设置多个y轴
      if (this.chartType === 'dual_axis') {
        option.yAxis = [getYAxisOption({ name: '折线图' }), getYAxisOption({ name: '柱状图', nameRotate: 270 })];
      }
      if (!Array.isArray(option.yAxis) && this.tooltipConfig?.type) {
        option.yAxis = getYAxisOption(option.yAxis);
        option.yAxis.axisLabel.formatter = getAxisFormatter(this.tooltipConfig.type);
      }
      if (this.chartType !== 'pie' && this.tooltipConfig?.markData && series[0]) {
        series[0].markLine = getMarkLineOption({
          data: this.tooltipConfig.markData,
        });
      }
      option.dataset = dataset;
      option.series = series;
      option.tooltip = tooltip;
      this.chartOption = merge(option, this.option);
    },

    handleChartDimensionChange() {
      this.setSeries();
      this.$emit('on-dimension-change');
    },

    handleIndexChange(val, i) {
      const arr = [...this.indexValue];
      arr.splice(i, 1, val);
      this.$emit('update:indexValue', arr);
      this.$emit('on-index-change');
    },

    handleDimensionChange(val) {
      this.$emit('update:dimensionValue', [val]);
      this.$emit('on-dimension-change');
    },

    handleChartTypeChange(val) {
      this.setSeries();
      this.$emit('on-type-change', val);
    },

    handleChartEdit() {
      this.$emit('on-edit');
    },

    handleChartDelete() {
      this.$emit('on-delete');
    },
  },
};
</script>
