<template>
  <div
    :style="{
      ...styleMap?.mainStyle
    }"
    class="relative w-full h-full box-border overflow-hidden"
  >
    <ImageBg
      v-if="styleMap?.mainStyle?.imageSrc"
      :src="styleMap?.mainStyle?.imageSrc"
      :imageStyle="styleMap?.mainStyle?.imageStyle"
    />

    <div class="absolute inset-0 w-full h-full">
      <svg
        :viewBox="`0 0 ${width} ${height}`"
        preserveAspectRatio="xMidYMid meet"
        class="w-full h-full block"
        xmlns="http://www.w3.org/2000/svg"
      >
        <!-- 网格线 -->
        <g v-if="hasGrid">
          <line
            v-for="(line, index) in verticalGridLines"
            :key="'v-' + index"
            :x1="line.x1"
            :y1="line.y1"
            :x2="line.x2"
            :y2="line.y2"
            :stroke="gridLineColor"
            :stroke-width="gridLineWidth"
            :stroke-dasharray="gridDashArray"
            :opacity="gridLineOpacity"
          />
          <line
            v-for="(line, index) in horizontalGridLines"
            :key="'h-' + index"
            :x1="line.x1"
            :y1="line.y1"
            :x2="line.x2"
            :y2="line.y2"
            :stroke="gridLineColor"
            :stroke-width="gridLineWidth"
            :stroke-dasharray="gridDashArray"
            :opacity="gridLineOpacity"
          />
        </g>

        <!-- 折线图 -->
        <g v-if="chart_type === 'line'">
          <path
            v-for="serie in lineSeries"
            :key="`line-${serie.key}`"
            :d="serie.path"
            fill="none"
            :stroke="serie.color"
            :stroke-width="2"
          />
          <g v-if="!hide_line_points">
            <circle
              v-for="point in linePoints"
              :key="point.key"
              :cx="point.x"
              :cy="point.y"
              r="3"
              :fill="point.color"
            />
          </g>
        </g>

        <!-- 柱状图 -->
        <g v-else-if="chart_type === 'bar'">
          <rect
            v-for="bar in barSeries"
            :key="bar.key"
            :x="bar.x"
            :y="bar.y"
            :width="bar.width"
            :height="bar.height"
            :fill="bar.color"
          />
        </g>
      </svg>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { useWidgetStyle } from '../hooks/useWidgetStyle'

import ImageBg from '../ImageBg.vue'
import type { DataSection } from './Config.vue'

const props = defineProps<{
  width: number
  height: number
  styles: any
  state?: string
  part?: string
  column: number
  row: number
  chart_type: 'line' | 'bar' | 'none'
  hide_line_points: boolean
  axis_y: {
    min: number
    max: number
  }
  open_axis_y2: boolean
  axis_y2?: {
    min: number
    max: number
  }
  chart_data: DataSection[]
}>()

const styleMap = useWidgetStyle({
  widget: 'lv_chart',
  props
})

// 主样式配置（获取折线虚线样式）
const mainStyleConfig = computed(() =>
  props.styles?.find(
    (s: any) =>
      s.part?.name === 'main' && (s.part?.state === props.state || s.part?.state === 'default')
  )
)

const gridLineWidth = computed(() => styleMap.value?.mainStyle?.line?.width ?? 1)
const gridLineColor = computed(() => styleMap.value?.mainStyle?.line?.color ?? '#e0e0e0')
const gridLineOpacity = computed(() => styleMap.value?.mainStyle?.line?.opacity ?? 1)

const gridDashArray = computed(() => {
  const dashWidth = mainStyleConfig.value?.line?.dashWidth ?? 0
  const dashGap = mainStyleConfig.value?.line?.dashGap ?? 0
  if (dashWidth > 0 || dashGap > 0) {
    return `${dashWidth} ${dashGap}`
  }
  return undefined
})

// 安全内边距，模拟 LVGL chart 的安全区域，避免图形/网格贴边框
const padding = 8

const innerLeft = computed(() => padding)
const innerRight = computed(() => Math.max(padding, props.width - padding))
const innerTop = computed(() => padding)
const innerBottom = computed(() => Math.max(padding, props.height - padding))

const innerWidth = computed(() => Math.max(0, innerRight.value - innerLeft.value))
const innerHeight = computed(() => Math.max(0, innerBottom.value - innerTop.value))

const hasGrid = computed(() => (props.column ?? 0) > 0 || (props.row ?? 0) > 0)

// 网格线
const verticalGridLines = computed(() => {
  const count = Math.max(0, props.column ?? 0)
  const lines: { x1: number; y1: number; x2: number; y2: number }[] = []
  if (!innerWidth.value || count <= 0) return lines

  // 从安全内边距开始计算：
  // column = 4 时，i = 0..3，第一条在左侧安全边距，最后一条在右侧安全边距，中间等分
  for (let i = 0; i < count; i++) {
    const t = count === 1 ? 0.5 : i / (count - 1)
    const x = innerLeft.value + t * innerWidth.value
    lines.push({
      x1: x,
      y1: 0,
      x2: x,
      y2: props.height
    })
  }
  return lines.length >= 2 ? lines : []
})

const horizontalGridLines = computed(() => {
  const count = Math.max(0, props.row ?? 0)
  const lines: { x1: number; y1: number; x2: number; y2: number }[] = []
  if (!innerHeight.value || count <= 0) return lines

  // 从安全内边距开始计算：
  // row = 4 时，i = 0..3，第一条在上侧安全边距，最后一条在下侧安全边距，中间等分
  for (let i = 0; i < count; i++) {
    const t = count === 1 ? 0.5 : i / (count - 1)
    const y = innerTop.value + t * innerHeight.value
    lines.push({
      x1: 0,
      y1: y,
      x2: props.width,
      y2: y
    })
  }
  return lines.length >= 2 ? lines : []
})

type AxisKey = 'y' | 'y2'

const getAxisRange = (axis: AxisKey) => {
  const cfg = axis === 'y2' && props.open_axis_y2 ? props.axis_y2 || props.axis_y : props.axis_y
  let min = Number(cfg?.min ?? 0)
  let max = Number(cfg?.max ?? 100)

  if (min === max) {
    const delta = Math.abs(min || 1)
    min -= delta
    max += delta
  }

  if (min > max) {
    const temp = min
    min = max
    max = temp
  }

  return { min, max }
}

const mapValueToY = (value: number, axis: AxisKey) => {
  const { min, max } = getAxisRange(axis)
  const span = max - min
  if (!innerHeight.value || span === 0) {
    return (innerTop.value + innerBottom.value) / 2
  }
  const t = (value - min) / span
  const clamped = Math.max(0, Math.min(1, t))
  return innerBottom.value - clamped * innerHeight.value
}

const mapIndexToX = (index: number, total: number) => {
  if (!innerWidth.value) {
    return (innerLeft.value + innerRight.value) / 2
  }
  if (total <= 1) {
    return innerLeft.value + innerWidth.value / 2
  }
  const t = index / (total - 1)
  return innerLeft.value + t * innerWidth.value
}

const seriesList = computed(() => (props.chart_data || []) as DataSection[])

// 折线图数据
const lineSeries = computed(() => {
  return seriesList.value.map((serie, index) => {
    const total = Array.isArray(serie.points) ? serie.points.length : 0
    const axis: AxisKey = serie.chart_axis === 'y2' ? 'y2' : 'y'

    if (!total || !innerWidth.value || !innerHeight.value) {
      return {
        key: serie.name || index,
        color: serie.color || '#2092f5ff',
        path: '',
        points: [] as { x: number; y: number; color: string; key: string }[]
      }
    }

    const points = serie.points.map((v, idx) => {
      const x = mapIndexToX(idx, total)
      const y = mapValueToY(v, axis)
      return {
        x,
        y,
        color: serie.color || '#2092f5ff',
        key: `${serie.name || index}-${idx}`
      }
    })

    const path = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ')

    return {
      key: serie.name || index,
      color: serie.color || '#2092f5ff',
      path,
      points
    }
  })
})

const linePoints = computed(() => lineSeries.value.flatMap((serie) => serie.points))

// 柱状图数据
const barSeries = computed(() => {
  const series = seriesList.value.filter((s) => Array.isArray(s.points) && s.points.length > 0)
  const seriesCount = series.length
  if (!seriesCount || !innerWidth.value || !innerHeight.value) return []

  const maxPointCount = series.reduce((max, s) => Math.max(max, s.points.length), 0)
  if (!maxPointCount) return []

  const groupSpace = innerWidth.value / maxPointCount
  const groupWidth = groupSpace * 0.7
  const barWidth = groupWidth / seriesCount
  const offsetInGroup = (groupSpace - groupWidth) / 2

  const bars: {
    key: string
    x: number
    y: number
    width: number
    height: number
    color: string
  }[] = []

  for (let i = 0; i < maxPointCount; i++) {
    const groupStart = innerLeft.value + i * groupSpace + offsetInGroup

    series.forEach((serie, sIndex) => {
      const v = serie.points[i]
      if (typeof v !== 'number') return
      const axis: AxisKey = serie.chart_axis === 'y2' ? 'y2' : 'y'

      const yValue = mapValueToY(v, axis)
      const baseY = mapValueToY(getAxisRange(axis).min, axis)
      const top = Math.min(yValue, baseY)
      const bottom = Math.max(yValue, baseY)

      bars.push({
        key: `${serie.name || sIndex}-${i}`,
        x: groupStart + sIndex * barWidth,
        y: top,
        width: barWidth,
        height: Math.max(1, bottom - top),
        color: serie.color || '#2092f5ff'
      })
    })
  }

  return bars
})
</script>
