<template>
  <view class="uni-charts">
    <canvas
        v-if="type !== 'map'"
        class="charts-canvas"
        :style="{width: width + 'px', height: height + 'px'}"
        canvas-id="uni-charts"
        @touchstart="touchStart"
        @touchmove="touchMove"
        @touchend="touchEnd"
    ></canvas>
    <view v-else class="map-container" :style="{width: width + 'px', height: height + 'px'}">
      <slot name="map"></slot>
    </view>
  </view>
</template>

<script>
export default {
  name: 'uniCharts',
  props: {
    type: {
      type: String,
      default: 'line'
    },
    data: {
      type: Array,
      default () {
        return []
      }
    },
    categories: {
      type: Array,
      default () {
        return []
      }
    },
    option: {
      type: Object,
      default () {
        return {
          yAxis: {
            tickCount: 5 // 默认5个刻度，可通过option自定义，无上限
          }
        }
      }
    },
    width: {
      type: [Number, String],
      default: 375
    },
    height: {
      type: [Number, String],
      default: 200
    }
  },
  data () {
    return {
      ctx: null,
      chartData: {},
      touchInfo: {}
    }
  },
  watch: {
    data: {
      deep: true,
      handler () {
        this.initChart()
      }
    },
    categories: {
      deep: true,
      handler () {
        this.initChart()
      }
    },
    option: {
      deep: true,
      handler () {
        this.initChart()
      }
    }
  },
  mounted () {
    this.initChart()
  },
  methods: {
    initChart () {
      if (this.type === 'kline') {
        this.drawKline()
      } else if (this.type === 'line') {
        this.drawLine()
      }
    },
    // 核心：自适应计算Y轴整数刻度（无任何数值限制）
    calculateYAxisTicks (minVal, maxVal, tickCount = 5) {
      // 1. 确保是整数，且最大值>最小值（无数值范围限制）
      minVal = parseInt(minVal, 10)
      maxVal = parseInt(maxVal, 10)

      // 边界处理：极值相等时自动扩展范围（避免刻度重复）
      if (maxVal <= minVal) {
        maxVal = minVal + tickCount // 扩展范围，保证刻度不重复
      }

      // 2. 动态计算整数步长（完全自适应，无固定值限制）
      const totalRange = maxVal - minVal
      let step = Math.ceil(totalRange / (tickCount - 1)) // 关键：按刻度数算步长
      step = step < 1 ? 1 : step // 步长至少为1，保证整数刻度

      // 3. 生成连续不重复的整数刻度（无数值上限）
      const ticks = []
      for (let i = 0; i < tickCount; i++) {
        ticks.push(minVal + i * step)
      }

      // 4. 确保最大值能覆盖数据（无限制）
      if (ticks[ticks.length - 1] < maxVal) {
        ticks.push(maxVal)
      }

      return {
        ticks: ticks, // 最终刻度数组（纯整数、不重复、无限制）
        min: minVal,
        max: Math.max(...ticks),
        step: step
      }
    },
    // 折线图绘制（无限制版）
    drawLine () {
      if (!this.data.length || !this.categories.length) return;

      const ctx = uni.createCanvasContext('uni-charts', this)
      this.ctx = ctx
      const { width, height } = this
      const {
        grid = {},
        xAxis = {},
        yAxis = {},
        legend = {},
        color = ['#25AF69', '#B34C17']
      } = this.option

      // 清空画布
      ctx.clearRect(0, 0, width, height)

      // Grid布局（自适应，无固定值）
      const gridTop = grid.top ? (typeof grid.top === 'string' ? parseFloat(grid.top) / 100 * height : grid.top) : 60
      const gridLeft = grid.left ? (typeof grid.left === 'string' ? parseFloat(grid.left) / 100 * width : grid.left) : 70
      const gridRight = grid.right ? (typeof grid.right === 'string' ? parseFloat(grid.right) / 100 * width : grid.right) : 20
      const gridBottom = grid.bottom ? (typeof grid.bottom === 'string' ? parseFloat(grid.bottom) / 100 * height : grid.bottom) : 50

      const drawWidth = width - gridLeft - gridRight
      const drawHeight = height - gridTop - gridBottom

      // 收集所有Y轴数据（无数值限制）
      let allValues = []
      this.data.forEach(series => {
        allValues = allValues.concat(series.data)
      })
      if (allValues.length === 0) return;

      // 基础极值（完全按数据来，无任何限制）
      const rawMaxVal = Math.max(...allValues)
      const rawMinVal = Math.min(...allValues)
      // 用户可通过yAxis.min/max自定义极值，否则用数据极值（无限制）
      const maxVal = yAxis.max !== undefined ? yAxis.max : rawMaxVal
      const minVal = yAxis.min !== undefined ? yAxis.min : rawMinVal
      // 刻度数量自定义（默认5个，可传任意数，无上限）
      const tickCount = yAxis.tickCount || 5

      // 核心：计算无限制、不重复的整数刻度
      const yAxisConfig = this.calculateYAxisTicks(minVal, maxVal, tickCount)
      const { ticks: yTicks, min: alignedMinVal, max: alignedMaxVal } = yAxisConfig
      const valRange = alignedMaxVal - alignedMinVal || 1

      // X轴步长（自适应）
      const xStep = drawWidth / (this.categories.length - 1 || 1)

      // X轴标签防拥挤（自适应，无限制）
      const minLabelWidth = 30
      const maxShowLabels = Math.floor(drawWidth / minLabelWidth)
      const labelInterval = maxShowLabels < this.categories.length
          ? Math.ceil(this.categories.length / maxShowLabels)
          : 1

      // 绘制网格线 + Y轴整数刻度（无数值限制）
      ctx.setStrokeStyle(yAxis.splitLine?.lineStyle?.color || '#f5f5f7')
      ctx.setLineWidth(1)

      yTicks.forEach((tickVal, i) => {
        const y = gridTop + drawHeight - (i * drawHeight / (yTicks.length - 1))
        // 绘制网格线
        ctx.beginPath()
        ctx.moveTo(gridLeft, y)
        ctx.lineTo(width - gridRight, y)
        ctx.stroke()

        // Y轴显示纯整数（无小数点、无任何数值限制）
        ctx.setFillStyle(yAxis.axisLabel?.color || '#666')
        ctx.setFontSize(yAxis.axisLabel?.fontSize || 12)
        const valText = tickVal.toString() // 纯整数，直接转字符串
        const textWidth = ctx.measureText(valText).width
        ctx.fillText(valText, gridLeft - 10 - textWidth, y + 5)
      })

      // 绘制X轴标签（自适应）
      ctx.setFillStyle(xAxis.axisLabel?.color || '#666')
      ctx.setFontSize(xAxis.axisLabel?.fontSize || 12)
      this.categories.forEach((text, index) => {
        if (index % labelInterval === 0) {
          const x = gridLeft + index * xStep
          let labelText = text
          if (text.length > 6) {
            labelText = text.slice(0, 6) + '...'
          }
          const textLines = labelText.split('\n')
          textLines.forEach((line, lineIdx) => {
            const textWidth = ctx.measureText(line).width
            ctx.fillText(line, x - textWidth / 2, height - gridBottom + 20 + (lineIdx * 12))
          })
        }
      })

      // 绘制图例（核心修复：颜色块和文字垂直居中对齐）
      if (legend.show) {
        // 获取图例文字大小（统一基准）
        const legendFontSize = legend.textStyle?.fontSize || 12
        ctx.setFontSize(legendFontSize)
        // 定义颜色块尺寸（和文字高度匹配）
        const legendBlockSize = legendFontSize * 0.8 // 颜色块大小 = 文字大小的80%，视觉更协调
        const legendBlockMargin = 5 // 颜色块和文字的间距
        let legendX = gridLeft + 10
        // 计算垂直居中基准线
        const legendYBase = gridTop - 30

        this.data.forEach((series, idx) => {
          let seriesName = series.name || `系列${idx + 1}`
          if (seriesName.length > 8) {
            seriesName = seriesName.slice(0, 8) + '...'
          }
          const textWidth = ctx.measureText(seriesName).width

          // 核心：计算颜色块和文字的垂直居中位置
          // 颜色块Y坐标 = 基准线 - 颜色块高度/2（居中）
          const legendBlockY = legendYBase - legendBlockSize / 2
          // 文字Y坐标 = 基准线 + 文字高度/4（canvas文字居中的黄金比例）
          const legendTextY = legendYBase + legendFontSize / 4

          // 绘制颜色块（居中对齐）
          ctx.setFillStyle(series.color || color[idx % color.length])
          ctx.fillRect(legendX, legendBlockY, legendBlockSize, legendBlockSize)

          // 绘制文字（和颜色块垂直居中）
          ctx.setFillStyle('#666')
          ctx.fillText(seriesName, legendX + legendBlockSize + legendBlockMargin, legendTextY)

          // 更新下一个图例的X坐标（包含间距）
          legendX += legendBlockSize + legendBlockMargin + textWidth + 10
        })
      }

      // 绘制折线（纯直线，无数值限制）
      this.data.forEach((series, seriesIdx) => {
        const seriesColor = series.color || color[seriesIdx % color.length]

        ctx.setStrokeStyle(seriesColor)
        ctx.setLineWidth(2)
        ctx.beginPath()

        series.data.forEach((value, index) => {
          const x = gridLeft + index * xStep
          // 自适应计算Y坐标（无数值限制）
          const y = gridTop + drawHeight - ((value - alignedMinVal) / valRange) * drawHeight

          if (index === 0) {
            ctx.moveTo(x, y)
          } else {
            ctx.lineTo(x, y)
          }
        })

        ctx.stroke()
      })

      ctx.draw()
    },
    // K线图绘制（同步无限制逻辑 + 图例对齐修复）
    drawKline () {
      const ctx = uni.createCanvasContext('uni-charts', this)
      this.ctx = ctx
      const { width, height } = this
      const { grid = {}, xAxis = {}, yAxis = {}, color = ['#B34C17', '#25AF69'] } = this.option

      ctx.clearRect(0, 0, width, height)

      // Grid布局（自适应）
      const gridTop = grid.top ? (typeof grid.top === 'string' ? parseFloat(grid.top) / 100 * height : grid.top) : 50
      const gridLeft = grid.left ? (typeof grid.left === 'string' ? parseFloat(grid.left) / 100 * width : grid.left) : 70
      const gridRight = grid.right ? (typeof grid.right === 'string' ? parseFloat(grid.right) / 100 * width : grid.right) : 20
      const gridBottom = grid.bottom ? (typeof grid.bottom === 'string' ? parseFloat(grid.bottom) / 100 * height : grid.bottom) : 40

      const drawWidth = width - gridLeft - gridRight
      const drawHeight = height - gridTop - gridBottom

      // 收集所有Y轴数据（无限制）
      let allValues = []
      this.data.forEach(item => {
        allValues = allValues.concat([item.open, item.high, item.low, item.close])
      })
      if (allValues.length === 0) return;

      // 基础极值（无限制）
      const rawMaxVal = Math.max(...allValues)
      const rawMinVal = Math.min(...allValues)
      const maxVal = yAxis.max !== undefined ? yAxis.max : rawMaxVal
      const minVal = yAxis.min !== undefined ? yAxis.min : rawMinVal
      const tickCount = yAxis.tickCount || 5

      // 核心：无限制整数刻度计算
      const yAxisConfig = this.calculateYAxisTicks(minVal, maxVal, tickCount)
      const { ticks: yTicks, min: alignedMinVal, max: alignedMaxVal } = yAxisConfig
      const valRange = alignedMaxVal - alignedMinVal || 1

      const xStep = drawWidth / (this.data.length || 1)

      // 绘制网格线和Y轴刻度（无限制）
      ctx.setStrokeStyle('#f5f5f7')
      ctx.setLineWidth(1)

      yTicks.forEach((tickVal, i) => {
        const y = gridTop + drawHeight - (i * drawHeight / (yTicks.length - 1))
        ctx.beginPath()
        ctx.moveTo(gridLeft, y)
        ctx.lineTo(width - gridRight, y)
        ctx.stroke()

        // 纯整数显示（无限制）
        ctx.setFillStyle(yAxis.axisLabel?.color || '#666')
        ctx.setFontSize(yAxis.axisLabel?.fontSize || 12)
        const valText = tickVal.toString()
        const textWidth = ctx.measureText(valText).width
        ctx.fillText(valText, gridLeft - 10 - textWidth, y + 5)
      })

      // X轴标签（自适应）
      ctx.setFillStyle(xAxis.axisLabel?.color || '#666')
      ctx.setFontSize(xAxis.axisLabel?.fontSize || 12)
      const minLabelWidth = 30
      const maxShowLabels = Math.floor(drawWidth / minLabelWidth)
      const labelInterval = maxShowLabels < this.categories.length
          ? Math.ceil(this.categories.length / maxShowLabels)
          : 1

      this.categories.forEach((text, index) => {
        if (index % labelInterval === 0) {
          const x = gridLeft + index * xStep + xStep / 2
          let labelText = text
          if (text.length > 6) labelText = text.slice(0, 6) + '...'
          ctx.fillText(labelText, x - ctx.measureText(labelText).width / 2, height - gridBottom + 20)
        }
      })

      // 绘制K线（无数值限制）
      this.data.forEach((item, index) => {
        const { open, high, low, close } = item
        const x = gridLeft + index * xStep + xStep / 2
        // 自适应坐标计算
        const yOpen = gridTop + drawHeight - ((open - alignedMinVal) / valRange) * drawHeight
        const yClose = gridTop + drawHeight - ((close - alignedMinVal) / valRange) * drawHeight
        const yHigh = gridTop + drawHeight - ((high - alignedMinVal) / valRange) * drawHeight
        const yLow = gridTop + drawHeight - ((low - alignedMinVal) / valRange) * drawHeight

        // 绘制高低线
        ctx.setStrokeStyle(close >= open ? color[0] : color[1])
        ctx.setLineWidth(1)
        ctx.beginPath()
        ctx.moveTo(x, yHigh)
        ctx.lineTo(x, yLow)
        ctx.stroke()

        // 绘制实体
        const rectWidth = xStep / 3
        ctx.setFillStyle(close >= open ? color[0] : color[1])
        const rectY = Math.min(yOpen, yClose)
        const rectHeight = Math.abs(yClose - yOpen) || 2
        ctx.fillRect(x - rectWidth / 2, rectY, rectWidth, rectHeight)
      })

      ctx.draw()
    },
    touchStart (e) {
      this.touchInfo = {
        x: e.changedTouches[0].x,
        y: e.changedTouches[0].y,
        time: Date.now()
      }
    },
    touchMove (e) {
      this.touchInfo.x = e.changedTouches[0].x
      this.touchInfo.y = e.changedTouches[0].y
    },
    touchEnd (e) {
      // 可扩展交互逻辑，无限制
    }
  }
}
</script>

<style scoped>
.uni-charts {
  position: relative;
}
.charts-canvas {
  display: block;
}
.map-container {
  position: relative;
}
</style>