import {
  G2PlotChartView,
  G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import type { Sankey, SankeyOptions } from '@antv/g2plot/esm/plots/sankey'
import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
import { cloneDeep, get } from 'lodash-es'
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
import { valueFormatter } from '@/views/chart/components/js/formatter'

import { Datum } from '@antv/g2plot/esm/types/common'
import { useI18n } from '@/hooks/web/useI18n'
import {
  SANKEY_AXIS_TYPE,
  SANKEY_EDITOR_PROPERTY,
  SANKEY_EDITOR_PROPERTY_INNER
} from '@/views/chart/components/js/panel/charts/others/sankey-common'

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

/**
 * 桑基图
 */
export class SankeyBar extends G2PlotChartView<SankeyOptions, Sankey> {
  axisConfig = {
    xAxis: {
      name: `${t('chart.drag_block_type_axis_start')} / ${t('chart.dimension')}`,
      limit: 1,
      type: 'd'
    },
    xAxisExt: {
      name: `${t('chart.drag_block_type_axis_end')} / ${t('chart.dimension')}`,
      limit: 1,
      type: 'd',
      allowEmpty: true
    },
    yAxis: {
      name: `${t('chart.chart_data')} / ${t('chart.quota')}`,
      limit: 1,
      type: 'q'
    }
  }
  properties = SANKEY_EDITOR_PROPERTY
  propertyInner = {
    ...SANKEY_EDITOR_PROPERTY_INNER,
    'label-selector': ['color', 'fontSize'],
    'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show']
  }
  axis: AxisType[] = [...SANKEY_AXIS_TYPE]
  protected baseOptions: SankeyOptions = {
    data: [],
    sourceField: 'source',
    targetField: 'target',
    weightField: 'value',
    rawFields: ['dimensionList', 'quotaList'],
    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: 'tooltip',
        cfg: {
          start: [{ trigger: 'interval:mousemove', action: 'tooltip:show' }],
          end: [{ trigger: 'interval:mouseleave', action: 'tooltip:hide' }]
        }
      },
      {
        type: 'active-region',
        cfg: {
          start: [{ trigger: 'interval:mousemove', action: 'active-region:show' }],
          end: [{ trigger: 'interval:mouseleave', action: 'active-region:hide' }]
        }
      }
    ]
  }

  async drawChart(drawOptions: G2PlotDrawOptions<Sankey>): Promise<Sankey> {
    const { chart, container, action } = drawOptions
    if (!chart.data?.data?.length) {
      return
    }
    // data
    const data: Array<any> = cloneDeep(chart.data.data)

    data.forEach(d => {
      if (d.dimensionList) {
        if (d.dimensionList[0]) {
          d.source = d.dimensionList[0].value
        }
        if (d.dimensionList[1]) {
          d.target = d.dimensionList[1].value
        }
      }
    })

    // options
    const initOptions: SankeyOptions = {
      ...this.baseOptions,
      appendPadding: getPadding(chart),
      data,
      nodeSort: (a, b) => {
        // 这里是前端自己排序
        if (chart.yAxis && chart.yAxis[0]) {
          if (chart.yAxis[0].sort === 'asc') {
            return a.value - b.value
          } else if (chart.yAxis[0].sort === 'desc') {
            return b.value - a.value
          }
        }

        if (chart.xAxis && chart.xAxis[0] && a.sourceLinks.length > 0) {
          if (chart.xAxis[0].sort === 'custom_sort' && chart.xAxis[0].customSort) {
            return (
              chart.xAxis[0].customSort.indexOf(a.name) - chart.xAxis[0].customSort.indexOf(b.name)
            )
          } else if (chart.xAxis[0].sort === 'asc') {
            return a.name.localeCompare(b.name)
          } else if (chart.xAxis[0].sort === 'desc') {
            return b.name.localeCompare(a.name)
          }
        }
        if (chart.xAxisExt && chart.xAxisExt[0] && a.targetLinks.length > 0) {
          if (chart.xAxisExt[0].sort === 'custom_sort' && chart.xAxisExt[0].customSort) {
            return (
              chart.xAxisExt[0].customSort.indexOf(a.name) -
              chart.xAxisExt[0].customSort.indexOf(b.name)
            )
          } else if (chart.xAxisExt[0].sort === 'asc') {
            return a.name.localeCompare(b.name)
          } else if (chart.xAxisExt[0].sort === 'desc') {
            return b.name.localeCompare(a.name)
          }
        }

        return b.value - a.value
      }
    }

    const options = this.setupOptions(chart, initOptions)
    const { Sankey } = await import('@antv/g2plot/esm/plots/sankey')
    // 开始渲染
    const newChart = new Sankey(container, options)

    newChart.on('edge:click', action)

    return newChart
  }

  protected configTooltip(chart: Chart, options: SankeyOptions): SankeyOptions {
    let tooltip
    let customAttr: DeepPartial<ChartAttr>
    if (chart.customAttr) {
      customAttr = parseJson(chart.customAttr)
      // tooltip
      if (customAttr.tooltip) {
        const t = JSON.parse(JSON.stringify(customAttr.tooltip))
        if (t.show) {
          // 计算每个source节点的总出
          const outTotal = {}
          if (Array.isArray(options.data)) {
            options.data?.forEach(d => {
              outTotal[d.source] = (outTotal[d.source] || 0) + d.value
            })
          }
          tooltip = {
            showTitle: false,
            showMarkers: false,
            shared: false,
            // 内置：node 不显示 tooltip，edge 显示 tooltip
            showContent: items => {
              return !get(items, [0, 'data', 'isNode'])
            },
            formatter: (datum: Datum) => {
              const { source, target, value } = datum
              // 总出占比
              if (t.tooltipFormatter.showTotalPercent) {
                const { decimalCount = 2 } = t.tooltipFormatter
                const ratioStr = ((value / outTotal[source]) * 100).toFixed(decimalCount) + '%'
                return {
                  name: `${source} -> ${target}`,
                  value: valueFormatter(value, t.tooltipFormatter) + ` (${ratioStr})`
                }
              }
              return {
                name: source + ' -> ' + target,
                value: valueFormatter(value, t.tooltipFormatter)
              }
            }
          }
        } else {
          tooltip = false
        }
      }
    }
    return { ...options, tooltip }
  }

  protected configBasicStyle(chart: Chart, options: SankeyOptions): SankeyOptions {
    const basicStyle = parseJson(chart.customAttr).basicStyle

    let color = basicStyle.colors
    color = color.map(ele => {
      const tmp = hexColorToRGBA(ele, basicStyle.alpha)
      if (basicStyle.gradient) {
        return setGradientColor(tmp, true)
      } else {
        return tmp
      }
    })

    options = {
      ...options,
      color
    }
    return options
  }

  setupDefaultOptions(chart: ChartObj): ChartObj {
    const { customAttr, senior } = chart
    const { label } = customAttr
    if (!['left', 'middle', 'right'].includes(label.position)) {
      label.position = 'middle'
    }
    senior.functionCfg.emptyDataStrategy = 'ignoreData'
    return chart
  }

  protected configLabel(chart: Chart, options: SankeyOptions): SankeyOptions {
    const labelAttr = parseJson(chart.customAttr).label
    if (labelAttr.show) {
      const layout = []
      if (!labelAttr.fullDisplay) {
        layout.push(...[{ type: 'hide-overlap' }, { type: 'limit-in-canvas' }])
      }
      const label = {
        //...tmpOptions.label,
        formatter: ({ name }) => name,
        callback: (x: number[]) => {
          const isLast = x[1] === 1 // 最后一列靠边的节点
          return {
            style: {
              fill: labelAttr.color,
              fontSize: labelAttr.fontSize,
              textAlign: isLast ? 'end' : 'start',
              fontFamily: chart.fontFamily
            },
            offsetX: isLast ? -8 : 8
          }
        },
        layout
      }
      return {
        ...options,
        label
      }
    } else {
      return {
        ...options,
        label: false
      }
    }
  }

  protected setupOptions(chart: Chart, options: SankeyOptions): SankeyOptions {
    return flow(
      this.configTheme,
      this.configBasicStyle,
      this.configLabel,
      this.configTooltip,
      this.configLegend,
      this.configSlider,
      this.configAnalyseHorizontal,
      this.configEmptyDataStrategy
    )(chart, options)
  }

  constructor(name = 'sankey') {
    super(name, DEFAULT_DATA)
  }
}
