<template>
  <div ref="chartContainer" class="chart-renderer" :style="{ height: `${height}px` }">
    <v-chart
      v-if="option"
      :option="option"
      :init-options="initOptions"
      autoresize
      class="echarts-instance"
    />
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { use } from 'echarts/core'
import { CanvasRenderer, SVGRenderer } from 'echarts/renderers'
import { BarChart, LineChart, PieChart, HeatmapChart } from 'echarts/charts'
import {
  TitleComponent,
  TooltipComponent,
  LegendComponent,
  GridComponent,
  DataZoomComponent,
  VisualMapComponent,
  CalendarComponent
} from 'echarts/components'
import VChart from 'vue-echarts'
import type { ComposeOption } from 'echarts/core'
import type { BarSeriesOption, LineSeriesOption, PieSeriesOption, HeatmapSeriesOption } from 'echarts/charts'
import type {
  TitleComponentOption,
  TooltipComponentOption,
  LegendComponentOption,
  GridComponentOption,
  DataZoomComponentOption,
  VisualMapComponentOption,
  CalendarComponentOption
} from 'echarts/components'
import type { ChartData, DashboardChartPg } from '@/shared/composables/useChartData'

use([
  SVGRenderer,
  CanvasRenderer,
  BarChart,
  LineChart,
  PieChart,
  HeatmapChart,
  TitleComponent,
  TooltipComponent,
  LegendComponent,
  GridComponent,
  DataZoomComponent,
  VisualMapComponent,
  CalendarComponent
])

type ECOption = ComposeOption<
  | BarSeriesOption
  | LineSeriesOption
  | PieSeriesOption
  | HeatmapSeriesOption
  | TitleComponentOption
  | TooltipComponentOption
  | LegendComponentOption
  | GridComponentOption
  | DataZoomComponentOption
  | VisualMapComponentOption
  | CalendarComponentOption
>

const props = withDefaults(defineProps<{
  data: ChartData | null
  config: DashboardChartPg | null
  colors?: string[]
  height?: number
  renderer?: 'svg' | 'canvas'
}>(), {
  colors: () => [],
  height: 240,
  renderer: 'svg'
})

const DEFAULT_COLORS = [
  '#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de',
  '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc', '#0d6efd'
]

const initOptions = computed(() => ({
  renderer: props.renderer
}))

const resolvedColors = computed(() => {
  const c = props.colors.filter(Boolean)
  return c.length > 0 ? c : DEFAULT_COLORS
})

const chartType = computed(() => {
  return props.config?.type || 'Bar'
})

const option = computed<ECOption | null>(() => {
  if (!props.data || !props.config) return null

  switch (chartType.value) {
    case 'Line':
      return buildLineBarOption('line')
    case 'Bar':
      return buildLineBarOption('bar')
    case 'Pie':
      return buildPieOption(false)
    case 'Donut':
      return buildPieOption(true)
    case 'Percentage':
      return buildPercentageOption()
    case 'Heatmap':
      return buildHeatmapOption()
    default:
      return buildLineBarOption('bar')
  }
})

function buildLineBarOption(type: 'line' | 'bar'): ECOption {
  const d = props.data!
  const labels = d.labels || []
  const datasets = d.datasets || []

  const series: Array<LineSeriesOption | BarSeriesOption> = datasets.map((ds, idx) => ({
    name: ds.name || '',
    type,
    data: ds.values || [],
    smooth: type === 'line',
    itemStyle: {
      color: resolvedColors.value[idx % resolvedColors.value.length]
    },
    emphasis: { focus: 'series' as const }
  }))

  return {
    color: resolvedColors.value,
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: type === 'bar' ? 'shadow' : 'cross' },
      formatter: tooltipFormatter
    },
    legend: datasets.length > 1 ? {
      bottom: 0,
      type: 'scroll',
      itemGap: 10,
      textStyle: { fontSize: 11 }
    } : undefined,
    grid: {
      left: '10%',
      right: '5%',
      bottom: datasets.length > 1 ? '22%' : '8%',
      top: '10%',
      containLabel: false
    },
    xAxis: {
      type: 'category',
      data: labels,
      axisLabel: {
        rotate: labels.length > 10 ? 45 : 0,
        fontSize: 11,
        hideOverlap: true,
        margin: 12
      },
      axisTick: { alignWithLabel: true }
    },
    yAxis: {
      type: 'value',
      axisLabel: {
        formatter: shortenNumber
      }
    },
    series
  }
}

function buildPieOption(isDonut: boolean): ECOption {
  const d = props.data!
  const labels = d.labels || []
  const datasets = d.datasets || []
  const values = datasets[0]?.values || []
  const maxSlices = props.config?.number_of_groups || 6

  let pieData: Array<{ name: string; value: number }> = labels.map((label, i) => ({
    name: label || 'N/A',
    value: values[i] || 0
  }))

  pieData.sort((a, b) => b.value - a.value)

  if (pieData.length > maxSlices) {
    const top = pieData.slice(0, maxSlices - 1)
    const rest = pieData.slice(maxSlices - 1)
    const otherVal = rest.reduce((sum, item) => sum + item.value, 0)
    top.push({ name: 'Others', value: otherVal })
    pieData = top
  }

  return {
    color: resolvedColors.value,
    tooltip: {
      trigger: 'item',
      formatter: '{b}: {c} ({d}%)'
    },
    legend: {
      type: 'scroll',
      bottom: 0,
      left: 'center'
    },
    series: [
      {
        type: 'pie',
        radius: isDonut ? ['40%', '70%'] : '70%',
        center: ['50%', '45%'],
        data: pieData,
        emphasis: {
          itemStyle: {
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: 'rgba(0, 0, 0, 0.5)'
          }
        },
        label: {
          show: true,
          formatter: '{b}: {d}%'
        }
      }
    ]
  }
}

function buildPercentageOption(): ECOption {
  const d = props.data!
  const labels = d.labels || []
  const datasets = d.datasets || []
  const values = datasets[0]?.values || []
  const total = values.reduce((s, v) => s + v, 0) || 1

  const barData = labels.map((label, i) => ({
    name: label || 'N/A',
    value: Number(((values[i] / total) * 100).toFixed(1))
  }))

  barData.sort((a, b) => b.value - a.value)

  return {
    color: resolvedColors.value,
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'shadow' },
      formatter: (params: any) => {
        const p = Array.isArray(params) ? params[0] : params
        return `${p.name}: ${p.value}%`
      }
    },
    grid: {
      left: '10%',
      right: '5%',
      bottom: '5%',
      top: '10%'
    },
    xAxis: {
      type: 'value',
      max: 100,
      axisLabel: { formatter: '{value}%' }
    },
    yAxis: {
      type: 'category',
      data: barData.map(d => d.name),
      axisLabel: { fontSize: 11 }
    },
    series: [
      {
        type: 'bar',
        data: barData.map((d, i) => ({
          value: d.value,
          itemStyle: { color: resolvedColors.value[i % resolvedColors.value.length] }
        })),
        label: {
          show: true,
          position: 'right',
          formatter: '{c}%'
        }
      }
    ]
  }
}

function buildHeatmapOption(): ECOption {
  const d = props.data!
  const dataPoints = d.dataPoints || {}

  const year = props.config?.heatmap_year || new Date().getFullYear()
  const calendarData: Array<[string, number]> = []
  let maxVal = 0

  for (const [ts, val] of Object.entries(dataPoints)) {
    const date = new Date(Number(ts) * 1000)
    const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
    const numVal = Number(val) || 0
    calendarData.push([dateStr, numVal])
    if (numVal > maxVal) maxVal = numVal
  }

  return {
    tooltip: {
      formatter: (params: any) => {
        const p = Array.isArray(params) ? params[0] : params
        return `${p.value[0]}: ${p.value[1]}`
      }
    },
    visualMap: {
      min: 0,
      max: maxVal || 1,
      show: true,
      orient: 'horizontal',
      left: 'center',
      bottom: 0,
      inRange: {
        color: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']
      }
    },
    calendar: {
      top: 30,
      left: 50,
      right: 30,
      cellSize: ['auto', 13],
      range: String(year),
      itemStyle: {
        borderWidth: 0.5,
        borderColor: '#fff'
      },
      yearLabel: { show: false },
      dayLabel: { fontSize: 10 },
      monthLabel: { fontSize: 11 }
    },
    series: [
      {
        type: 'heatmap',
        coordinateSystem: 'calendar',
        data: calendarData
      }
    ]
  }
}

function tooltipFormatter(params: any): string {
  if (!Array.isArray(params)) params = [params]
  let result = `<div style="font-weight:600;margin-bottom:4px">${params[0]?.axisValue || ''}</div>`
  params.forEach((p: any) => {
    const color = p.color || '#333'
    const marker = `<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:${color};margin-right:6px"></span>`
    result += `<div>${marker}${p.seriesName}: <strong>${formatNumber(p.value)}</strong></div>`
  })
  return result
}

function shortenNumber(value: number): string {
  if (Math.abs(value) >= 1e9) return (value / 1e9).toFixed(1) + 'B'
  if (Math.abs(value) >= 1e6) return (value / 1e6).toFixed(1) + 'M'
  if (Math.abs(value) >= 1e3) return (value / 1e3).toFixed(1) + 'K'
  return String(value)
}

function formatNumber(value: number): string {
  if (value == null) return '0'
  return Number(value).toLocaleString()
}
</script>

<style scoped>
.chart-renderer {
  width: 100%;
  min-height: 200px;
}

.echarts-instance {
  width: 100%;
  height: 100%;
}
</style>
