import {
  G2PlotChartView,
  G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import type { Gauge as G2Gauge, GaugeOptions } from '@antv/g2plot/esm/plots/gauge'
import { flow, parseJson } from '@/views/chart/components/js/util'
import {
  DEFAULT_LABEL,
  DEFAULT_MISC,
  DEFAULT_THRESHOLD,
  getScaleValue
} from '@/views/chart/components/editor/util/chart'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
import { useI18n } from '@/hooks/web/useI18n'
import { merge } from 'lodash-es'

const { t } = useI18n()

const DEFAULT_DATA = []
export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
  properties: EditorProperty[] = [
    'background-overall-component',
    'border-style',
    'basic-style-selector',
    'label-selector',
    'misc-selector',
    'title-selector',
    'threshold'
  ]
  propertyInner: EditorPropertyInner = {
    'background-overall-component': ['all'],
    'border-style': ['all'],
    'basic-style-selector': ['colors', 'alpha', 'gradient', 'gaugeAxisLine', 'gaugePercentLabel'],
    'label-selector': ['fontSize', 'color', 'labelFormatter'],
    'title-selector': [
      'title',
      'fontSize',
      'color',
      'hPosition',
      'isItalic',
      'isBolder',
      'remarkShow',
      'fontFamily',
      'letterSpace',
      'fontShadow'
    ],
    'misc-selector': [
      'gaugeMinType',
      'gaugeMinField',
      'gaugeMin',
      'gaugeMaxType',
      'gaugeMaxField',
      'gaugeMax',
      'gaugeStartAngle',
      'gaugeEndAngle'
    ],
    threshold: ['gaugeThreshold']
  }
  axis: AxisType[] = ['yAxis', 'filter']
  axisConfig: AxisConfig = {
    yAxis: {
      name: `${t('chart.drag_block_gauge_angel')} / ${t('chart.quota')}`,
      type: 'q',
      limit: 1
    }
  }

  async drawChart(drawOptions: G2PlotDrawOptions<G2Gauge>): Promise<G2Gauge> {
    const { chart, container, scale, action } = drawOptions
    if (!chart.data?.series || !chart.yAxis.length) {
      return
    }
    // options
    const initOptions: GaugeOptions = {
      percent: 0,
      appendPadding: [0, 10, 15, 10],
      axis: {
        tickInterval: 0.2,
        label: {
          style: {
            fontSize: getScaleValue(12, scale) // 刻度值字体大小
          }
        },
        tickLine: {
          length: getScaleValue(12, scale) * -1, // 刻度线长度
          style: {
            lineWidth: getScaleValue(1, scale) // 刻度线宽度
          }
        },
        subTickLine: {
          count: 4, // 子刻度数
          length: getScaleValue(6, scale) * -1, // 子刻度线长度
          style: {
            lineWidth: getScaleValue(1, scale) // 子刻度线宽度
          }
        }
      }
    }
    const options = this.setupOptions(chart, initOptions, { scale })
    const { Gauge: G2Gauge } = await import('@antv/g2plot/esm/plots/gauge')
    const newChart = new G2Gauge(container, options)
    newChart.on('afterrender', () => {
      action({
        from: 'gauge',
        data: {
          type: 'gauge',
          max: chart.data?.series[0]?.data[0]
        }
      })
    })
    const hasNoneData = chart.data?.series.some(
      s => s.data?.[0] === undefined || s.data?.[0] === null
    )
    this.configEmptyDataStyle(hasNoneData ? [] : [1], container, newChart)
    if (hasNoneData) {
      return
    }
    return newChart
  }

  protected configMisc(
    chart: Chart,
    options: GaugeOptions,
    context: Record<string, any>
  ): GaugeOptions {
    const customAttr = parseJson(chart.customAttr)
    const data = chart.data.series[0].data[0]
    let min, max, startAngle, endAngle
    if (customAttr.misc) {
      const misc = customAttr.misc
      if (misc.gaugeMinType === 'dynamic' && misc.gaugeMaxType === 'dynamic') {
        min = chart.data?.series[chart.data?.series.length - 2]?.data[0]
        max = chart.data?.series[chart.data?.series.length - 1]?.data[0]
      } else if (misc.gaugeMinType !== 'dynamic' && misc.gaugeMaxType === 'dynamic') {
        min = misc.gaugeMin || misc.gaugeMin === 0 ? misc.gaugeMin : DEFAULT_MISC.gaugeMin
        max = chart.data?.series[chart.data?.series.length - 1]?.data[0]
      } else if (misc.gaugeMinType === 'dynamic' && misc.gaugeMaxType !== 'dynamic') {
        min = chart.data?.series[chart.data?.series.length - 1]?.data[0]
        max = misc.gaugeMax ? misc.gaugeMax : DEFAULT_MISC.gaugeMax
      } else {
        min = misc.gaugeMin || misc.gaugeMin === 0 ? misc.gaugeMin : DEFAULT_MISC.gaugeMin
        max = misc.gaugeMax
          ? misc.gaugeMax
          : chart.data?.series[chart.data?.series.length - 1]?.data[0]
      }
      startAngle = (misc.gaugeStartAngle * Math.PI) / 180
      endAngle = (misc.gaugeEndAngle * Math.PI) / 180
      context.min = min
      context.max = max
    }
    const percent = (parseFloat(data) - parseFloat(min)) / (parseFloat(max) - parseFloat(min))
    const tmp = {
      percent,
      startAngle,
      endAngle
    }
    return { ...options, ...tmp }
  }

  private configRange(
    chart: Chart,
    options: GaugeOptions,
    context: Record<string, any>
  ): GaugeOptions {
    const { scale } = context
    const range = [0]
    let index = 0
    let flag = false
    let hasThreshold = false
    const theme = options.theme as any

    if (chart.senior) {
      const senior = parseJson(chart.senior)
      const threshold = senior.threshold ?? DEFAULT_THRESHOLD
      if (threshold.enable && threshold.gaugeThreshold) {
        hasThreshold = true
        const arr = threshold.gaugeThreshold.split(',')
        for (let i = 0; i < arr.length; i++) {
          const ele = arr[i]
          const p = parseFloat(ele) / 100
          range.push(p)
          if (!flag && options.percent <= p) {
            flag = true
            index = i
          }
        }
        if (!flag) {
          index = arr.length
        }
      }
    }
    range.push(1)
    let rangOptions
    if (hasThreshold) {
      rangOptions = {
        range: {
          color: theme.styleSheet.paletteQualitative10,
          ticks: range
        },
        indicator: {
          pointer: {
            style: {
              stroke:
                theme.styleSheet.paletteQualitative10[
                  index % theme.styleSheet.paletteQualitative10.length
                ]
            }
          },
          pin: {
            style: {
              stroke:
                theme.styleSheet.paletteQualitative10[
                  index % theme.styleSheet.paletteQualitative10.length
                ],
              r: getScaleValue(10, scale)
            }
          }
        }
      }
    } else {
      rangOptions = {
        indicator: {
          pin: {
            style: {
              r: getScaleValue(10, scale)
            }
          }
        }
      }
    }
    const customAttr = parseJson(chart.customAttr)
    if (customAttr.basicStyle.gradient) {
      const colorList = (theme.styleSheet?.paletteQualitative10 || []).map(ele => {
        return setGradientColor(ele, true)
      })
      if (!rangOptions.range) {
        rangOptions.range = {
          color: colorList
        }
      } else {
        rangOptions.range.color = colorList
      }
    }
    return { ...options, ...rangOptions }
  }

  protected configLabel(
    chart: Chart,
    options: GaugeOptions,
    context?: Record<string, any>
  ): GaugeOptions {
    const customAttr = parseJson(chart.customAttr)
    const data = chart.data.series[0].data[0]
    let labelTitle: GaugeOptions['statistic']['title'] = false
    let labelContent: GaugeOptions['statistic']['content'] = false
    const label = customAttr.label
    const labelFormatter = label.labelFormatter ?? DEFAULT_LABEL.labelFormatter
    if (label.show && label.childrenShow) {
      labelTitle = {
        style: {
          fontSize: `${label.fontSize}px`,
          color: label.color
        },
        formatter: function () {
          return valueFormatter(data, labelFormatter)
        }
      } as GaugeOptions['statistic']['title']
    }
    const { min, max } = context
    if (label.show && label.proportionSeriesFormatter.show) {
      const proportionFormatter = label.proportionSeriesFormatter
      labelContent = {
        offsetY: proportionFormatter.fontSize + label.fontSize,
        style: {
          fontSize: `${proportionFormatter.fontSize}px`,
          color: proportionFormatter.color
        },
        formatter: function () {
          const proportionValue = ((parseFloat(data) - min) / (max - min)) * 100
          return (
            t('chart.proportion') +
            '： ' +
            proportionValue.toFixed(proportionFormatter.formatterCfg.decimalCount) +
            '%'
          )
        }
      } as GaugeOptions['statistic']['content']
    }
    const statistic = {
      title: labelTitle,
      content: labelContent
    }
    const { gaugeAxisLine, gaugePercentLabel } = customAttr.basicStyle
    const tmp = {
      axis: {
        label: {
          formatter: v => {
            if (gaugeAxisLine === false) {
              return ''
            }
            if (gaugePercentLabel === false) {
              const resultV = v === '0' ? min : v === '1' ? max : min + (max - min) * v
              return labelFormatter.type === 'value'
                ? valueFormatter(resultV, labelFormatter)
                : resultV
            }
            return v === '0' ? v : v * 100 + '%'
          }
        }
      }
    }
    options = merge(options, tmp)
    return { ...options, statistic }
  }

  setupDefaultOptions(chart: ChartObj): ChartObj {
    chart.customAttr.label = {
      ...chart.customAttr.label,
      show: true,
      labelFormatter: {
        type: 'value',
        thousandSeparator: true,
        decimalCount: 0,
        unit: 1
      }
    }
    return chart
  }

  protected setupOptions(
    chart: Chart,
    options: GaugeOptions,
    context: Record<string, any>
  ): GaugeOptions {
    return flow(
      this.configTheme,
      this.configMisc,
      this.configLabel,
      this.configRange
    )(chart, options, context)
  }
  constructor() {
    super('gauge', DEFAULT_DATA)
  }
}
