import type {
  AnyChartInput,
  LineChartInput,
  PieChartInput,
  BarChartInput,
  HeatmapChartInput,
} from '@/types/chart'

function buildMarkLine(input: any) {
  const custom = input?.markLine
  const avg = input?.avgLine
  if (custom) return custom
  if (avg == null) return undefined
  return {
    silent: true,
    symbol: 'none',
    lineStyle: { type: 'dashed', color: '#6B7280' },
    label: {
      position: 'middle',
      formatter: `Avg: ${avg}`,
      color: '#374151',
      backgroundColor: 'rgba(255,255,255,0.9)',
      padding: [2, 6],
      borderRadius: 3,
    },
    data: [[{ coord: ['min', avg] }, { coord: ['max', avg] }]],
  }
}

function toolboxBottomRight(withLegend: boolean, noToolbox?: boolean) {
  if (noToolbox) return undefined
  return {
    right: 10,
    bottom: withLegend ? 6 : 10,
    itemSize: 18,
    itemGap: 12,
    iconStyle: { color: '#9CA3AF', borderColor: '#9CA3AF' },
    emphasis: { iconStyle: { color: '#2AB1AC' } },
    feature: {
      saveAsImage: { pixelRatio: 2, name: 'chart', title: 'Save image' },
      dataView: { readOnly: true, title: 'Data view' },
      restore: { title: 'Restore' },
    },
  } as const
}

// LINE
export function toLineOption(input: LineChartInput): any {
  const isTime = input.xIsDate === true
  const yName = (input as any).yAxisName ?? input.yUnit
  const xName = (input as any).xAxisName
  const leftPad = Math.min(96, 20 + 8 * (yName?.length ?? 0))
  const many = input.x.length > 90
  const noToolbox = (input as any).noToolbox === true

  const option: any = {
    tooltip: { trigger: 'axis', confine: true },
    legend: { type: 'scroll', top: 0 },
    grid: {
      left: leftPad,
      right: 24,
      top: input.title ? 64 : 40,
      bottom: many ? 96 : 64,
      containLabel: true,
    },
    xAxis: {
      type: isTime ? 'time' : 'category',
      ...(isTime ? {} : { data: input.x }),
      name: xName,
      nameGap: 20,
      axisLabel: { hideOverlap: true },
    },
    yAxis: {
      type: 'value',
      name: yName,
      nameLocation: 'middle',
      nameGap: 42,
      axisLabel: { hideOverlap: true },
    },
    series: input.series.map((s) => ({
      name: s.name,
      type: 'line',
      symbol: 'circle',
      symbolSize: 5,
      showSymbol: false,
      smooth: true,
      data: isTime ? input.x.map((x, i) => [x as any, s.data[i]]) : s.data,
      emphasis: { focus: 'series' },
    })),
    dataZoom: many
      ? [
          { type: 'inside', throttle: 50 },
          { type: 'slider', height: 18, bottom: 30 },
        ]
      : undefined,
    toolbox: toolboxBottomRight(true, noToolbox),
  }

  const markLine = buildMarkLine(input as any)
  if (markLine)
    option.series.forEach((s: any) => {
      s.markLine = markLine
    })
  return option
}

// PIE
export function toPieOption(input: PieChartInput): any {
  const donut = !!input.donut
  const noToolbox = (input as any).noToolbox === true
  return {
    tooltip: { trigger: 'item' },
    legend: { orient: 'horizontal', top: 0 },
    series: [
      {
        type: 'pie',
        radius: donut ? ['45%', '70%'] : '65%',
        center: ['50%', '55%'],
        label: { formatter: '{b}: {d}%' },
        data: input.series.map((s) => ({ name: s.name, value: s.value })),
        emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0 } },
      },
    ],
    toolbox: toolboxBottomRight(false, noToolbox),
  } as const
}

// BAR
export function toBarOption(input: BarChartInput): any {
  const many = input.x.length > 20
  const yName = (input as any).yAxisName ?? input.yUnit
  const xName = (input as any).xAxisName
  const leftPad = Math.min(96, 20 + 8 * (yName?.length ?? 0))
  const noToolbox = (input as any).noToolbox === true

  const option: any = {
    tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' }, confine: true },
    legend: { type: 'scroll', top: 0 },
    grid: { left: leftPad, right: 24, top: input.title ? 64 : 40, bottom: 64, containLabel: true },
    xAxis: {
      type: 'category',
      data: input.x,
      name: xName,
      nameGap: 24,
      axisLabel: { hideOverlap: true, rotate: input.x.length > 8 ? 45 : 0 },
      boundaryGap: true,
    },
    yAxis: {
      type: 'value',
      name: yName,
      nameLocation: 'middle',
      nameGap: 42,
      axisLabel: { hideOverlap: true },
      splitLine: { show: true },
    },
    series: input.series.map((s) => ({
      name: s.name,
      type: 'bar',
      data: s.data,
      barMaxWidth: 36,
      emphasis: { focus: 'series' },
      stack: input.stacked ? 'total' : undefined,
    })),
    dataZoom: many
      ? [
          { type: 'inside', throttle: 50 },
          { type: 'slider', height: 18, bottom: 30 },
        ]
      : undefined,
    toolbox: toolboxBottomRight(true, noToolbox),
  }

  const markLine = buildMarkLine(input as any)
  if (markLine)
    option.series.forEach((s: any) => {
      s.markLine = markLine
    })
  return option
}

// HEATMAP
export function toHeatmapOption(input: HeatmapChartInput): any {
  const values = input.data.map((d) => d[2] as number)
  const min = Math.min(...values)
  const max = Math.max(...values)
  const noToolbox = (input as any).noToolbox === true

  return {
    tooltip: { position: 'top' },
    grid: { left: 60, right: 40, top: input.title ? 60 : 24, bottom: 48 },
    xAxis: {
      type: 'category',
      data: input.x,
      splitArea: { show: true },
      axisLabel: { hideOverlap: true, rotate: input.x.length > 10 ? 45 : 0 },
    },
    yAxis: { type: 'category', data: input.y, splitArea: { show: true } },
    visualMap: { min, max, dimension: 2, orient: 'horizontal', left: 'center', bottom: -20 },
    series: [
      {
        type: 'heatmap',
        data: input.data,
        encode: { x: 0, y: 1, value: 2 },
        emphasis: { itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0,0,0,0.2)' } },
        progressive: 0,
      },
    ],
    toolbox: toolboxBottomRight(false, noToolbox),
  } as const
}

export function buildOption(input: AnyChartInput): any {
  if (input.kind === 'line') return toLineOption(input as LineChartInput)
  if (input.kind === 'pie') return toPieOption(input as PieChartInput)
  if (input.kind === 'bar') return toBarOption(input as BarChartInput)
  if (input.kind === 'heatmap') return toHeatmapOption(input as HeatmapChartInput)
  throw new Error(`Unsupported chart kind: ${(input as any)?.kind}`)
}
