import {
  G2PlotChartView,
  G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import type { DualAxes, DualAxesOptions } from '@antv/g2plot/esm/plots/dual-axes'
import {
  configRoundAngle,
  configPlotTooltipEvent,
  getAnalyse,
  getLabel,
  getPadding,
  getTooltipContainer,
  getYAxis,
  getYAxisExt,
  setGradientColor,
  TOOLTIP_TPL
} from '../../common/common_antv'
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
import {
  cloneDeep,
  isEmpty,
  defaultTo,
  map,
  filter,
  union,
  defaultsDeep,
  defaults
} from 'lodash-es'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import {
  CHART_MIX_AXIS_TYPE,
  CHART_MIX_DEFAULT_BASIC_STYLE,
  CHART_MIX_EDITOR_PROPERTY,
  CHART_MIX_EDITOR_PROPERTY_INNER,
  MixChartBasicStyle
} from './chart-mix-common'
import type { Datum } from '@antv/g2plot/esm/types/common'
import { useI18n } from '@/hooks/web/useI18n'
import {
  DEFAULT_BASIC_STYLE,
  DEFAULT_LABEL,
  DEFAULT_LEGEND_STYLE
} from '@/views/chart/components/editor/util/chart'
import type { Options } from '@antv/g2plot/esm'
import { Group } from '@antv/g-canvas'
import { extremumEvt } from '@/views/chart/components/js/extremumUitl'

const { t } = useI18n()
const DEFAULT_DATA = []

/**
 * 柱线混合图
 */
export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
  properties = CHART_MIX_EDITOR_PROPERTY
  propertyInner = {
    ...CHART_MIX_EDITOR_PROPERTY_INNER,
    'label-selector': ['vPosition', 'seriesLabelFormatter'],
    'tooltip-selector': [
      ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
      'seriesTooltipFormatter',
      'carousel'
    ]
  }
  axis: AxisType[] = [...CHART_MIX_AXIS_TYPE, 'xAxisExtRight', 'yAxisExt']
  axisConfig = {
    xAxis: {
      name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`,
      type: 'd'
    },
    yAxis: {
      name: `${t('chart.drag_block_value_axis_left')} / ${t('chart.column_quota')}`,
      limit: 1,
      type: 'q'
    },
    extBubble: {
      //用这个字段存放右轴分类
      name: `${t('chart.drag_block_type_axis_right')} / ${t('chart.dimension')}`,
      limit: 1,
      type: 'd',
      allowEmpty: true
    },
    yAxisExt: {
      name: `${t('chart.drag_block_value_axis_right')} / ${t('chart.line_quota')}`,
      limit: 1,
      type: 'q',
      allowEmpty: true
    }
  }

  protected getLeftType(): string {
    return 'column'
  }
  protected getRightType(): string {
    return 'line'
  }

  async drawChart(drawOptions: G2PlotDrawOptions<DualAxes>): Promise<DualAxes> {
    const { chart, action, container } = drawOptions
    chart.container = container
    if (!chart.data?.left?.data?.length && !chart.data?.right?.data?.length) {
      return
    }
    const left = cloneDeep(chart.data?.left?.data)
    const right = cloneDeep(chart.data?.right?.data)

    // const data1Type = (left[0]?.type === 'bar' ? 'column' : left[0]?.type) ?? 'column'
    // const data2Type = (right[0]?.type === 'bar' ? 'column' : right[0]?.type) ?? 'column'
    const data1Type = this.getLeftType()
    const data2Type = this.getRightType()

    const isGroup = this.name === 'chart-mix-group' && chart.xAxisExt?.length > 0
    const isStack = this.name === 'chart-mix-stack' && chart.extStack?.length > 0
    const seriesField = 'category'
    const seriesField2 = 'category'

    const data1 = defaultTo(left[0]?.data, [])
    const data2 = map(defaultTo(right[0]?.data, []), d => {
      return {
        ...d,
        valueExt: d.value
      }
    })
    // options
    const initOptions: DualAxesOptions = {
      data: [data1, data2],
      xField: 'field',
      yField: ['value', 'valueExt'], //这里不能设置成一样的
      appendPadding: getPadding(chart),
      geometryOptions: [
        {
          geometry: data1Type,
          marginRatio: 0,
          color: [],
          isGroup: isGroup,
          isStack: isStack,
          seriesField: seriesField
        },
        {
          geometry: data2Type,
          color: [],
          seriesField: seriesField2
        }
      ],
      interactions: [
        {
          type: 'legend-active',
          cfg: {
            start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }],
            end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }]
          }
        },
        {
          type: 'legend-filter',
          cfg: {
            start: [
              {
                trigger: 'legend-item:click',
                action: [
                  'list-unchecked:toggle',
                  'data-filter:filter',
                  'element-active:reset',
                  'element-highlight:reset'
                ]
              }
            ]
          }
        },
        {
          type: 'active-region'
        }
      ]
    }
    const options = this.setupOptions(chart, initOptions)
    const { DualAxes } = await import('@antv/g2plot/esm/plots/dual-axes')
    // 开始渲染
    const newChart = new DualAxes(container, options)

    newChart.on('point:click', action)
    newChart.on('interval:click', action)
    extremumEvt(newChart, chart, options, container)
    configPlotTooltipEvent(chart, newChart)
    return newChart
  }

  protected configLabel(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    const tempLabel = getLabel(chart)
    const tmpOption = { ...options }
    if (!tempLabel) {
      if (tmpOption.geometryOptions) {
        tmpOption.geometryOptions[0].label = false
        tmpOption.geometryOptions[1].label = false
      }
      return tmpOption
    }

    const labelAttr = parseJson(chart.customAttr).label
    const axisFormatterMap = {}
    labelAttr.seriesLabelFormatter?.forEach(attr => {
      if (!axisFormatterMap[attr.axisType]) {
        axisFormatterMap[attr.axisType] = []
      }
      axisFormatterMap[attr.axisType].push(attr)
    })
    const axisTypes = ['yAxis', 'yAxisExt']
    axisTypes.forEach(axisType => {
      const formatterMap = axisFormatterMap[axisType]?.reduce((pre, next) => {
        pre[next.id] = next
        return pre
      }, {})
      const textBaseline =
        this.getLeftType() === 'line' ? 'bottom' : axisType === 'yAxis' ? 'top' : 'bottom'
      tempLabel.style.fill = DEFAULT_LABEL.color
      const label = {
        fields: [],
        ...tempLabel,
        formatter: (data: Datum) => {
          if (!labelAttr.seriesLabelFormatter?.length) {
            return data.value
          }
          const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter
          if (!labelCfg) {
            return data.value
          }
          if (!labelCfg.show) {
            return
          }
          const value = valueFormatter(data.value, labelCfg.formatterCfg)
          const group = new Group({})
          group.addShape({
            type: 'text',
            attrs: {
              x: 0,
              y: 0,
              text: value,
              textAlign: 'start',
              textBaseline,
              fontSize: labelCfg.fontSize,
              fontFamily: chart.fontFamily,
              fill: labelCfg.color
            }
          })
          return group
        }
      }
      if (tmpOption.geometryOptions) {
        if (axisType === 'yAxis') {
          tmpOption.geometryOptions[0].label = label
        } else if (axisType === 'yAxisExt') {
          tmpOption.geometryOptions[1].label = label
        }
      }
    })

    return tmpOption
  }

  protected configBasicStyle(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    // size
    const customAttr: DeepPartial<ChartAttr> = parseJson(chart.customAttr)
    const s = defaultsDeep(
      JSON.parse(JSON.stringify(customAttr.basicStyle)),
      CHART_MIX_DEFAULT_BASIC_STYLE
    )
    const smooth = s.lineSmooth
    const point = {
      size: s.lineSymbolSize,
      shape: s.lineSymbol,
      style: {
        stroke: hexColorToRGBA('#FFFFFF', s.subAlpha)
      }
    }
    const lineStyle = {
      lineWidth: s.lineWidth
    }
    const leftSmooth = s.leftLineSmooth
    const leftPoint = {
      size: s.leftLineSymbolSize,
      shape: s.leftLineSymbol,
      style: {
        stroke: hexColorToRGBA('#FFFFFF', s.alpha)
      }
    }
    const leftLineStyle = {
      lineWidth: s.leftLineWidth
    }
    const tempOption = {
      ...options,
      smooth,
      point,
      lineStyle
    }
    if (tempOption.geometryOptions) {
      tempOption.geometryOptions[0].smooth = leftSmooth
      tempOption.geometryOptions[0].point = leftPoint
      tempOption.geometryOptions[0].lineStyle = leftLineStyle

      tempOption.geometryOptions[1].smooth = smooth
      tempOption.geometryOptions[1].point = point
      tempOption.geometryOptions[1].lineStyle = lineStyle
      tempOption.geometryOptions[0] = {
        ...tempOption.geometryOptions[0],
        ...configRoundAngle(chart, 'columnStyle')
      }
    }

    let columnWidthRatio
    const _v = s.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio
    if (_v >= 1 && _v <= 100) {
      columnWidthRatio = _v / 100.0
    } else if (_v < 1) {
      columnWidthRatio = 1 / 100.0
    } else if (_v > 100) {
      columnWidthRatio = 1
    }
    if (columnWidthRatio) {
      tempOption.geometryOptions[0].columnWidthRatio = columnWidthRatio
    }

    if (super.name !== 'chart-mix-dual-line') {
      tempOption.geometryOptions[0].appendPadding = getPadding(chart)
    }

    return tempOption
  }

  setupDefaultOptions(chart: ChartObj): ChartObj {
    const { senior } = chart
    if (
      senior.functionCfg.emptyDataStrategy == undefined ||
      senior.functionCfg.emptyDataStrategy === 'ignoreData'
    ) {
      senior.functionCfg.emptyDataStrategy = 'breakLine'
    }
    return chart
  }

  protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    const tempOption = {
      ...options
    }
    const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle

    const { seriesColor } = basicStyle
    if (seriesColor?.length) {
      const seriesMap = seriesColor.reduce((p, n) => {
        p[n.id] = n
        return p
      }, {})
      const { yAxis } = chart
      yAxis?.forEach((axis, index) => {
        const curAxisColor = seriesMap[axis.id]
        if (curAxisColor) {
          if (index + 1 > basicStyle.colors.length) {
            basicStyle.colors.push(curAxisColor.color)
          } else {
            basicStyle.colors[index] = curAxisColor.color
          }
        }
      })
    }
    //左轴
    const color = basicStyle.colors.map(ele => {
      const tmp = hexColorToRGBA(ele, basicStyle.alpha)
      if (basicStyle.gradient) {
        return setGradientColor(tmp, true, 270)
      } else {
        return tmp
      }
    })
    tempOption.geometryOptions[0].color = color

    return tempOption
  }

  protected configSubCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    const tempOption = {
      ...options
    }
    const basicStyle = defaultsDeep(
      parseJson(chart.customAttr).basicStyle as MixChartBasicStyle,
      cloneDeep(CHART_MIX_DEFAULT_BASIC_STYLE)
    )
    //右轴
    const { subSeriesColor } = basicStyle
    if (subSeriesColor?.length) {
      const { yAxisExt, extBubble } = chart
      const seriesMap = subSeriesColor.reduce((p, n) => {
        p[n.id] = n
        return p
      }, {})
      const { data } = options as unknown as Options
      if (extBubble?.length) {
        const seriesSet = new Set()
        data[1]?.forEach(d => d.category !== null && seriesSet.add(d.category))
        const tmp = [...seriesSet]
        tmp.forEach((c, i) => {
          const curAxisColor = seriesMap[c as string]
          if (curAxisColor) {
            if (i + 1 > basicStyle.subColors.length) {
              basicStyle.subColors.push(curAxisColor.color)
            } else {
              basicStyle.subColors[i] = curAxisColor.color
            }
          }
        })
      } else {
        yAxisExt?.forEach((axis, index) => {
          const curAxisColor = seriesMap[axis.id]
          if (curAxisColor) {
            if (index + 1 > basicStyle.subColors.length) {
              basicStyle.subColors.push(curAxisColor.color)
            } else {
              basicStyle.subColors[index] = curAxisColor.color
            }
          }
        })
      }
    }
    const subColor = basicStyle.subColors.map(c => {
      const cc = hexColorToRGBA(c, basicStyle.subAlpha)
      return cc
    })
    tempOption.geometryOptions[1].color = subColor

    return tempOption
  }

  public setupSubSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
    const result: ChartBasicStyle['seriesColor'] = []
    const seriesSet = new Set<string>()
    const colors = chart.customAttr.basicStyle.subColors ?? CHART_MIX_DEFAULT_BASIC_STYLE.subColors
    const { yAxisExt, extBubble } = chart
    if (extBubble?.length) {
      data?.forEach(d => {
        if (d.value === null || d.category === null || seriesSet.has(d.category)) {
          return
        }
        seriesSet.add(d.category)
        result.push({
          id: d.category,
          name: d.category,
          color: colors[(seriesSet.size - 1) % colors.length]
        })
      })
    } else {
      yAxisExt?.forEach(axis => {
        if (seriesSet.has(axis.id)) {
          return
        }
        seriesSet.add(axis.id)
        result.push({
          id: axis.id,
          name: axis.chartShowName ?? axis.name,
          color: colors[(seriesSet.size - 1) % colors.length]
        })
      })
    }
    return result
  }

  protected configYAxis(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    const yAxis = getYAxis(chart)
    const yAxisExt = getYAxisExt(chart)

    const tempOption = {
      ...options
    }

    tempOption.yAxis = {}
    if (!yAxis) {
      //左右轴都要隐藏
      tempOption.yAxis.value = false
    } else {
      tempOption.yAxis.value = undefined
      yAxis.position = 'left'

      const yAxisTmp = parseJson(chart.customStyle).yAxis
      if (yAxis.label) {
        yAxis.label.style.textAlign = 'end'
        yAxis.label.formatter = value => {
          return valueFormatter(value, yAxisTmp.axisLabelFormatter)
        }
      }
      const axisValue = yAxisTmp.axisValue
      if (!axisValue?.auto) {
        tempOption.yAxis.value = {
          ...yAxis,
          min: axisValue.min,
          max: axisValue.max,
          minLimit: axisValue.min,
          maxLimit: axisValue.max,
          tickCount: axisValue.splitCount
        }
      } else {
        tempOption.yAxis.value = yAxis
      }
    }

    if (!yAxisExt) {
      //左右轴都要隐藏
      tempOption.yAxis.valueExt = false
    } else {
      tempOption.yAxis.valueExt = undefined
      yAxisExt.position = 'right'

      const yAxisExtTmp = parseJson(chart.customStyle).yAxisExt
      if (yAxisExt.label) {
        yAxisExt.label.style.textAlign = 'start'
        yAxisExt.label.formatter = value => {
          return valueFormatter(value, yAxisExtTmp.axisLabelFormatter)
        }
      }
      const axisExtValue = yAxisExtTmp.axisValue
      if (!axisExtValue?.auto) {
        tempOption.yAxis.valueExt = {
          ...yAxisExt,
          min: axisExtValue.min,
          max: axisExtValue.max,
          minLimit: axisExtValue.min,
          maxLimit: axisExtValue.max,
          tickCount: axisExtValue.splitCount
        }
      } else {
        tempOption.yAxis.valueExt = yAxisExt
      }
    }

    return tempOption
  }

  protected configTooltip(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    const customAttr: DeepPartial<ChartAttr> = parseJson(chart.customAttr)
    const tooltipAttr = customAttr.tooltip
    if (!tooltipAttr.show) {
      return {
        ...options,
        tooltip: false
      }
    }
    const formatterMap = tooltipAttr.seriesTooltipFormatter
      ?.filter(i => i.show)
      .reduce((pre, next) => {
        pre[next.id] = next
        return pre
      }, {}) as Record<string, SeriesFormatter>
    const tooltip: DualAxesOptions['tooltip'] = {
      shared: true,
      showTitle: true,
      customItems(originalItems) {
        if (!tooltipAttr.seriesTooltipFormatter?.length) {
          return originalItems
        }
        const head = originalItems[0]
        // 非原始数据
        if (!head.data.quotaList) {
          return originalItems
        }
        const result = []
        originalItems
          .filter(item => formatterMap[item.data.quotaList[0].id])
          .forEach(item => {
            const formatter = formatterMap[item.data.quotaList[0].id]
            const value = valueFormatter(parseFloat(item.value as string), formatter.formatterCfg)
            const name = item.data.category

            result.push({ ...item, name, value })
          })
        head.data.dynamicTooltipValue?.forEach(item => {
          const formatter = formatterMap[item.fieldId]
          if (formatter) {
            const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg)
            const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName
            result.push({ color: 'grey', name, value })
          }
        })
        return result
      },
      container: getTooltipContainer(`tooltip-${chart.id}`),
      itemTpl: TOOLTIP_TPL,
      enterable: true
    }
    return {
      ...options,
      tooltip
    }
  }

  protected configLegend(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    const o = super.configLegend(chart, options)
    if (o.legend) {
      const left = cloneDeep(chart.data?.left?.data)
      const right = cloneDeep(chart.data?.right?.data)

      o.legend.itemName.formatter = (text: string, item: any, index: number) => {
        let name = undefined
        if (item.viewId === 'left-axes-view' && text === 'value') {
          name = left[0]?.categories[0]
        } else if (item.viewId === 'right-axes-view' && text === 'valueExt') {
          name = right[0]?.categories[0]
        }
        item.id = item.id + '__' + index //防止重复的图例出现问题，但是左右轴如果有相同的怎么办
        if (name === undefined) {
          return text
        } else {
          return name
        }
      }

      const customStyle = parseJson(chart.customStyle)
      let size
      if (customStyle && customStyle.legend) {
        size = defaults(JSON.parse(JSON.stringify(customStyle.legend)), DEFAULT_LEGEND_STYLE).size
      } else {
        size = DEFAULT_LEGEND_STYLE.size
      }

      o.legend.marker.style = style => {
        const fill = style.fill ?? style.stroke
        return {
          r: size,
          fill
        }
      }
    }
    return o
  }

  protected configAnalyse(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    chart.data.dynamicAssistLines = union(
      defaultTo(chart.data?.left?.dynamicAssistLines, []),
      defaultTo(chart.data?.right?.dynamicAssistLines, [])
    )
    const list = getAnalyse(chart)
    const annotations = {
      value: filter(list, l => l.yAxisType === 'left'),
      valueExt: filter(list, l => l.yAxisType === 'right')
    }
    return { ...options, annotations }
  }

  protected setupOptions(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    return flow(
      this.configTheme,
      this.configLabel,
      this.configTooltip,
      this.configBasicStyle,
      this.configCustomColors,
      this.configSubCustomColors,
      this.configLegend,
      this.configXAxis,
      this.configYAxis,
      this.configAnalyse,
      this.configEmptyDataStrategy
    )(chart, options, {}, this)
  }

  constructor(name = 'chart-mix') {
    super(name, DEFAULT_DATA)
  }
}

export class GroupColumnLineMix extends ColumnLineMix {
  axis: AxisType[] = [...this['axis'], 'xAxisExt']
  propertyInner = {
    ...CHART_MIX_EDITOR_PROPERTY_INNER,
    'label-selector': ['vPosition', 'seriesLabelFormatter'],
    'tooltip-selector': [
      ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
      'seriesTooltipFormatter',
      'carousel'
    ]
  }
  axisConfig = {
    ...this['axisConfig'],
    xAxisExt: {
      name: `${t('chart.chart_group')} / ${t('chart.dimension')}`,
      type: 'd',
      limit: 1,
      allowEmpty: true
    }
  }

  protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    const tempOption = {
      ...options
    }
    const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle

    const { seriesColor } = basicStyle
    if (seriesColor?.length) {
      const seriesMap = seriesColor.reduce((p, n) => {
        p[n.id] = n
        return p
      }, {})
      const { yAxis, xAxisExt } = chart
      const { data } = options as unknown as Options
      if (xAxisExt?.length) {
        const seriesSet = new Set()
        data[0]?.forEach(d => d.category !== null && seriesSet.add(d.category))
        const tmp = [...seriesSet]
        tmp.forEach((c, i) => {
          const curAxisColor = seriesMap[c as string]
          if (curAxisColor) {
            if (i + 1 > basicStyle.colors.length) {
              basicStyle.colors.push(curAxisColor.color)
            } else {
              basicStyle.colors[i] = curAxisColor.color
            }
          }
        })
      } else {
        yAxis?.forEach((axis, index) => {
          const curAxisColor = seriesMap[axis.id]
          if (curAxisColor) {
            if (index + 1 > basicStyle.colors.length) {
              basicStyle.colors.push(curAxisColor.color)
            } else {
              basicStyle.colors[index] = curAxisColor.color
            }
          }
        })
      }
    }
    //左轴
    const color = basicStyle.colors.map(ele => {
      const tmp = hexColorToRGBA(ele, basicStyle.alpha)
      if (basicStyle.gradient) {
        return setGradientColor(tmp, true, 270)
      } else {
        return tmp
      }
    })
    tempOption.geometryOptions[0].color = color

    return tempOption
  }

  public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
    const result: ChartBasicStyle['seriesColor'] = []
    const seriesSet = new Set<string>()
    const colors = chart.customAttr.basicStyle.colors
    const { yAxis, xAxisExt } = chart
    if (xAxisExt?.length) {
      data?.forEach(d => {
        if (d.value === null || d.category === null || seriesSet.has(d.category)) {
          return
        }
        seriesSet.add(d.category)
        result.push({
          id: d.category,
          name: d.category,
          color: colors[(seriesSet.size - 1) % colors.length]
        })
      })
    } else {
      yAxis?.forEach(axis => {
        if (seriesSet.has(axis.id)) {
          return
        }
        seriesSet.add(axis.id)
        result.push({
          id: axis.id,
          name: axis.chartShowName ?? axis.name,
          color: colors[(seriesSet.size - 1) % colors.length]
        })
      })
    }
    return result
  }

  constructor(name = 'chart-mix-group') {
    super(name)
  }
}
export class StackColumnLineMix extends ColumnLineMix {
  axis: AxisType[] = [...this['axis'], 'extStack']
  propertyInner = {
    ...CHART_MIX_EDITOR_PROPERTY_INNER,
    'label-selector': ['vPosition', 'seriesLabelFormatter'],
    'tooltip-selector': [
      ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
      'seriesTooltipFormatter',
      'carousel'
    ]
  }
  axisConfig = {
    ...this['axisConfig'],
    extStack: {
      name: `${t('chart.stack_item')} / ${t('chart.dimension')}`,
      type: 'd',
      limit: 1,
      allowEmpty: true
    }
  }

  protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    const tempOption = {
      ...options
    }
    const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle

    const { seriesColor } = basicStyle
    if (seriesColor?.length) {
      const seriesMap = seriesColor.reduce((p, n) => {
        p[n.id] = n
        return p
      }, {})
      const { yAxis, extStack } = chart
      const { data } = options as unknown as Options
      if (extStack?.length) {
        const seriesSet = new Set()
        data[0]?.forEach(d => d.category !== null && seriesSet.add(d.category))
        const tmp = [...seriesSet]
        tmp.forEach((c, i) => {
          const curAxisColor = seriesMap[c as string]
          if (curAxisColor) {
            if (i + 1 > basicStyle.colors.length) {
              basicStyle.colors.push(curAxisColor.color)
            } else {
              basicStyle.colors[i] = curAxisColor.color
            }
          }
        })
      } else {
        yAxis?.forEach((axis, index) => {
          const curAxisColor = seriesMap[axis.id]
          if (curAxisColor) {
            if (index + 1 > basicStyle.colors.length) {
              basicStyle.colors.push(curAxisColor.color)
            } else {
              basicStyle.colors[index] = curAxisColor.color
            }
          }
        })
      }
    }
    //左轴
    const color = basicStyle.colors.map(ele => {
      const tmp = hexColorToRGBA(ele, basicStyle.alpha)
      if (basicStyle.gradient) {
        return setGradientColor(tmp, true, 270)
      } else {
        return tmp
      }
    })
    tempOption.geometryOptions[0].color = color

    return tempOption
  }

  public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
    const result: ChartBasicStyle['seriesColor'] = []
    const seriesSet = new Set<string>()
    const colors = chart.customAttr.basicStyle.colors
    const { yAxis, extStack } = chart
    if (extStack?.length) {
      data?.forEach(d => {
        if (d.value === null || d.category === null || seriesSet.has(d.category)) {
          return
        }
        seriesSet.add(d.category)
        result.push({
          id: d.category,
          name: d.category,
          color: colors[(seriesSet.size - 1) % colors.length]
        })
      })
    } else {
      yAxis?.forEach(axis => {
        if (seriesSet.has(axis.id)) {
          return
        }
        seriesSet.add(axis.id)
        result.push({
          id: axis.id,
          name: axis.chartShowName ?? axis.name,
          color: colors[(seriesSet.size - 1) % colors.length]
        })
      })
    }
    return result
  }

  constructor(name = 'chart-mix-stack') {
    super(name)
  }
}

export class DualLineMix extends ColumnLineMix {
  axis: AxisType[] = [...this['axis'], 'xAxisExt']
  propertyInner = {
    ...CHART_MIX_EDITOR_PROPERTY_INNER,
    'label-selector': ['seriesLabelFormatter'],
    'tooltip-selector': [
      ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
      'seriesTooltipFormatter',
      'carousel'
    ]
  }
  axisConfig = {
    ...this['axisConfig'],
    xAxisExt: {
      name: `${t('chart.drag_block_type_axis_left')} / ${t('chart.dimension')}`,
      type: 'd',
      limit: 1,
      allowEmpty: true
    }
  }

  protected getLeftType(): string {
    return 'line'
  }

  protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions {
    const tempOption = {
      ...options
    }
    const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle

    const { seriesColor } = basicStyle
    if (seriesColor?.length) {
      const seriesMap = seriesColor.reduce((p, n) => {
        p[n.id] = n
        return p
      }, {})
      const { yAxis, xAxisExt } = chart
      const { data } = options as unknown as Options
      if (xAxisExt?.length) {
        const seriesSet = new Set()
        data[0]?.forEach(d => d.category !== null && seriesSet.add(d.category))
        const tmp = [...seriesSet]
        tmp.forEach((c, i) => {
          const curAxisColor = seriesMap[c as string]
          if (curAxisColor) {
            if (i + 1 > basicStyle.colors.length) {
              basicStyle.colors.push(curAxisColor.color)
            } else {
              basicStyle.colors[i] = curAxisColor.color
            }
          }
        })
      } else {
        yAxis?.forEach((axis, index) => {
          const curAxisColor = seriesMap[axis.id]
          if (curAxisColor) {
            if (index + 1 > basicStyle.colors.length) {
              basicStyle.colors.push(curAxisColor.color)
            } else {
              basicStyle.colors[index] = curAxisColor.color
            }
          }
        })
      }
    }
    //左轴
    const color = basicStyle.colors.map(ele => {
      const tmp = hexColorToRGBA(ele, basicStyle.alpha)
      if (basicStyle.gradient) {
        return setGradientColor(tmp, true, 270)
      } else {
        return tmp
      }
    })
    tempOption.geometryOptions[0].color = color

    return tempOption
  }

  public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
    const result: ChartBasicStyle['seriesColor'] = []
    const seriesSet = new Set<string>()
    const colors = chart.customAttr.basicStyle.colors
    const { yAxis, xAxisExt } = chart
    if (xAxisExt?.length) {
      data?.forEach(d => {
        if (d.value === null || d.category === null || seriesSet.has(d.category)) {
          return
        }
        seriesSet.add(d.category)
        result.push({
          id: d.category,
          name: d.category,
          color: colors[(seriesSet.size - 1) % colors.length]
        })
      })
    } else {
      yAxis?.forEach(axis => {
        if (seriesSet.has(axis.id)) {
          return
        }
        seriesSet.add(axis.id)
        result.push({
          id: axis.id,
          name: axis.chartShowName ?? axis.name,
          color: colors[(seriesSet.size - 1) % colors.length]
        })
      })
    }
    return result
  }

  constructor(name = 'chart-mix-dual-line') {
    super(name)
  }
}
