<template>
  <view class="chart-container">
    <canvas
      :canvas-id="canvasId"
      :id="canvasId"
      class="chart-canvas"
      :style="{ width: width + 'rpx', height: height + 'rpx' }"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
    />
    
    <!-- 图例 -->
    <view class="chart-legend" v-if="showLegend && legendData.length">
      <view
        class="legend-item"
        v-for="(item, index) in legendData"
        :key="index"
        @click="handleLegendClick(index)"
      >
        <view
          class="legend-color"
          :style="{ backgroundColor: item.color }"
        />
        <text class="legend-text">{{ item.name }}</text>
      </view>
    </view>
    
    <!-- 数据标签 -->
    <view class="chart-tooltip" v-if="showTooltip" :style="tooltipStyle">
      <view class="tooltip-content">
        <text class="tooltip-title">{{ tooltipData.title }}</text>
        <view
          class="tooltip-item"
          v-for="(item, index) in tooltipData.items"
          :key="index"
        >
          <view
            class="tooltip-color"
            :style="{ backgroundColor: item.color }"
          />
          <text class="tooltip-label">{{ item.label }}:</text>
          <text class="tooltip-value">{{ item.value }}</text>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
import { ref, reactive, computed, watch, onMounted, nextTick } from 'vue'

export default {
  name: 'Chart',
  props: {
    // 图表类型
    type: {
      type: String,
      default: 'line', // line, bar, pie, doughnut, area
      validator: (value) => ['line', 'bar', 'pie', 'doughnut', 'area'].includes(value)
    },
    // 图表数据
    data: {
      type: Object,
      required: true
    },
    // 图表配置
    options: {
      type: Object,
      default: () => ({})
    },
    // 画布尺寸
    width: {
      type: Number,
      default: 600
    },
    height: {
      type: Number,
      default: 400
    },
    // 是否显示图例
    showLegend: {
      type: Boolean,
      default: true
    },
    // 是否显示工具提示
    enableTooltip: {
      type: Boolean,
      default: true
    },
    // 是否启用动画
    animation: {
      type: Boolean,
      default: true
    },
    // 动画持续时间
    animationDuration: {
      type: Number,
      default: 1000
    }
  },
  emits: ['click', 'legendClick'],
  setup(props, { emit }) {
    const canvasId = `chart-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
    const ctx = ref(null)
    const showTooltip = ref(false)
    const tooltipData = ref({ title: '', items: [] })
    const tooltipStyle = ref({})
    const legendData = ref([])
    
    // 默认配置
    const defaultOptions = {
      responsive: true,
      maintainAspectRatio: false,
      padding: { top: 20, right: 20, bottom: 20, left: 20 },
      grid: {
        show: true,
        color: '#e5e5e5',
        lineWidth: 1
      },
      axis: {
        x: {
          show: true,
          color: '#666',
          fontSize: 24,
          labelRotate: 0
        },
        y: {
          show: true,
          color: '#666',
          fontSize: 24,
          min: null,
          max: null
        }
      },
      colors: [
        '#2e8b57', '#ff4757', '#3742fa', '#ffa502',
        '#7bed9f', '#ff6b81', '#70a1ff', '#ffb8b8'
      ]
    }
    
    // 合并配置
    const chartOptions = computed(() => {
      return Object.assign({}, defaultOptions, props.options)
    })
    
    // 初始化画布
    const initCanvas = () => {
      return new Promise((resolve) => {
        nextTick(() => {
          const query = uni.createSelectorQuery()
          query.select(`#${canvasId}`).fields({ node: true, size: true }).exec((res) => {
            if (res[0]) {
              const canvas = res[0].node
              const context = canvas.getContext('2d')
              
              // 设置画布尺寸
              const dpr = uni.getSystemInfoSync().pixelRatio
              canvas.width = props.width * dpr
              canvas.height = props.height * dpr
              context.scale(dpr, dpr)
              
              ctx.value = context
              resolve(context)
            }
          })
        })
      })
    }
    
    // 绘制图表
    const drawChart = async () => {
      if (!ctx.value) {
        await initCanvas()
      }
      
      if (!ctx.value || !props.data) return
      
      // 清空画布
      ctx.value.clearRect(0, 0, props.width, props.height)
      
      // 根据图表类型绘制
      switch (props.type) {
        case 'line':
          drawLineChart()
          break
        case 'bar':
          drawBarChart()
          break
        case 'pie':
          drawPieChart()
          break
        case 'doughnut':
          drawDoughnutChart()
          break
        case 'area':
          drawAreaChart()
          break
      }
      
      // 更新图例
      updateLegend()
    }
    
    // 绘制折线图
    const drawLineChart = () => {
      const { labels, datasets } = props.data
      const options = chartOptions.value
      const padding = options.padding
      
      const chartWidth = props.width - padding.left - padding.right
      const chartHeight = props.height - padding.top - padding.bottom
      const startX = padding.left
      const startY = padding.top
      
      // 计算数据范围
      const allValues = datasets.flatMap(dataset => dataset.data)
      const minValue = options.axis.y.min ?? Math.min(...allValues)
      const maxValue = options.axis.y.max ?? Math.max(...allValues)
      const valueRange = maxValue - minValue || 1
      
      // 绘制网格
      if (options.grid.show) {
        drawGrid(startX, startY, chartWidth, chartHeight, labels.length, 5)
      }
      
      // 绘制坐标轴
      drawAxis(startX, startY, chartWidth, chartHeight, labels, minValue, maxValue)
      
      // 绘制数据线
      datasets.forEach((dataset, datasetIndex) => {
        const color = dataset.color || options.colors[datasetIndex % options.colors.length]
        
        ctx.value.strokeStyle = color
        ctx.value.lineWidth = dataset.lineWidth || 2
        ctx.value.beginPath()
        
        dataset.data.forEach((value, index) => {
          const x = startX + (index / (labels.length - 1)) * chartWidth
          const y = startY + chartHeight - ((value - minValue) / valueRange) * chartHeight
          
          if (index === 0) {
            ctx.value.moveTo(x, y)
          } else {
            ctx.value.lineTo(x, y)
          }
        })
        
        ctx.value.stroke()
        
        // 绘制数据点
        if (dataset.showPoints !== false) {
          ctx.value.fillStyle = color
          dataset.data.forEach((value, index) => {
            const x = startX + (index / (labels.length - 1)) * chartWidth
            const y = startY + chartHeight - ((value - minValue) / valueRange) * chartHeight
            
            ctx.value.beginPath()
            ctx.value.arc(x, y, dataset.pointRadius || 4, 0, 2 * Math.PI)
            ctx.value.fill()
          })
        }
      })
    }
    
    // 绘制柱状图
    const drawBarChart = () => {
      const { labels, datasets } = props.data
      const options = chartOptions.value
      const padding = options.padding
      
      const chartWidth = props.width - padding.left - padding.right
      const chartHeight = props.height - padding.top - padding.bottom
      const startX = padding.left
      const startY = padding.top
      
      // 计算数据范围
      const allValues = datasets.flatMap(dataset => dataset.data)
      const minValue = Math.min(0, Math.min(...allValues))
      const maxValue = Math.max(...allValues)
      const valueRange = maxValue - minValue || 1
      
      // 绘制网格
      if (options.grid.show) {
        drawGrid(startX, startY, chartWidth, chartHeight, labels.length, 5)
      }
      
      // 绘制坐标轴
      drawAxis(startX, startY, chartWidth, chartHeight, labels, minValue, maxValue)
      
      // 计算柱子宽度
      const barGroupWidth = chartWidth / labels.length
      const barWidth = barGroupWidth / datasets.length * 0.8
      const barSpacing = barGroupWidth * 0.1
      
      // 绘制柱子
      datasets.forEach((dataset, datasetIndex) => {
        const color = dataset.color || options.colors[datasetIndex % options.colors.length]
        ctx.value.fillStyle = color
        
        dataset.data.forEach((value, index) => {
          const x = startX + index * barGroupWidth + datasetIndex * barWidth + barSpacing
          const barHeight = Math.abs(value - minValue) / valueRange * chartHeight
          const y = startY + chartHeight - barHeight
          
          ctx.value.fillRect(x, y, barWidth, barHeight)
        })
      })
    }
    
    // 绘制饼图
    const drawPieChart = () => {
      const { labels, datasets } = props.data
      const dataset = datasets[0]
      const options = chartOptions.value
      
      const centerX = props.width / 2
      const centerY = props.height / 2
      const radius = Math.min(props.width, props.height) / 2 - 40
      
      const total = dataset.data.reduce((sum, value) => sum + value, 0)
      let currentAngle = -Math.PI / 2
      
      dataset.data.forEach((value, index) => {
        const sliceAngle = (value / total) * 2 * Math.PI
        const color = dataset.colors?.[index] || options.colors[index % options.colors.length]
        
        ctx.value.fillStyle = color
        ctx.value.beginPath()
        ctx.value.moveTo(centerX, centerY)
        ctx.value.arc(centerX, centerY, radius, currentAngle, currentAngle + sliceAngle)
        ctx.value.closePath()
        ctx.value.fill()
        
        // 绘制标签
        if (options.showLabels !== false) {
          const labelAngle = currentAngle + sliceAngle / 2
          const labelX = centerX + Math.cos(labelAngle) * (radius * 0.7)
          const labelY = centerY + Math.sin(labelAngle) * (radius * 0.7)
          
          ctx.value.fillStyle = '#fff'
          ctx.value.font = '24px sans-serif'
          ctx.value.textAlign = 'center'
          ctx.value.textBaseline = 'middle'
          
          const percentage = ((value / total) * 100).toFixed(1)
          ctx.value.fillText(`${percentage}%`, labelX, labelY)
        }
        
        currentAngle += sliceAngle
      })
    }
    
    // 绘制环形图
    const drawDoughnutChart = () => {
      const { labels, datasets } = props.data
      const dataset = datasets[0]
      const options = chartOptions.value
      
      const centerX = props.width / 2
      const centerY = props.height / 2
      const outerRadius = Math.min(props.width, props.height) / 2 - 40
      const innerRadius = outerRadius * 0.6
      
      const total = dataset.data.reduce((sum, value) => sum + value, 0)
      let currentAngle = -Math.PI / 2
      
      dataset.data.forEach((value, index) => {
        const sliceAngle = (value / total) * 2 * Math.PI
        const color = dataset.colors?.[index] || options.colors[index % options.colors.length]
        
        // 绘制外圆弧
        ctx.value.fillStyle = color
        ctx.value.beginPath()
        ctx.value.arc(centerX, centerY, outerRadius, currentAngle, currentAngle + sliceAngle)
        ctx.value.arc(centerX, centerY, innerRadius, currentAngle + sliceAngle, currentAngle, true)
        ctx.value.closePath()
        ctx.value.fill()
        
        currentAngle += sliceAngle
      })
      
      // 绘制中心文字
      if (options.centerText) {
        ctx.value.fillStyle = '#333'
        ctx.value.font = 'bold 32px sans-serif'
        ctx.value.textAlign = 'center'
        ctx.value.textBaseline = 'middle'
        ctx.value.fillText(options.centerText, centerX, centerY)
      }
    }
    
    // 绘制面积图
    const drawAreaChart = () => {
      const { labels, datasets } = props.data
      const options = chartOptions.value
      const padding = options.padding
      
      const chartWidth = props.width - padding.left - padding.right
      const chartHeight = props.height - padding.top - padding.bottom
      const startX = padding.left
      const startY = padding.top
      
      // 计算数据范围
      const allValues = datasets.flatMap(dataset => dataset.data)
      const minValue = Math.min(0, Math.min(...allValues))
      const maxValue = Math.max(...allValues)
      const valueRange = maxValue - minValue || 1
      
      // 绘制网格
      if (options.grid.show) {
        drawGrid(startX, startY, chartWidth, chartHeight, labels.length, 5)
      }
      
      // 绘制坐标轴
      drawAxis(startX, startY, chartWidth, chartHeight, labels, minValue, maxValue)
      
      // 绘制面积
      datasets.forEach((dataset, datasetIndex) => {
        const color = dataset.color || options.colors[datasetIndex % options.colors.length]
        
        // 创建渐变
        const gradient = ctx.value.createLinearGradient(0, startY, 0, startY + chartHeight)
        gradient.addColorStop(0, color + '80') // 50% 透明度
        gradient.addColorStop(1, color + '20') // 12.5% 透明度
        
        ctx.value.fillStyle = gradient
        ctx.value.beginPath()
        
        // 绘制面积路径
        dataset.data.forEach((value, index) => {
          const x = startX + (index / (labels.length - 1)) * chartWidth
          const y = startY + chartHeight - ((value - minValue) / valueRange) * chartHeight
          
          if (index === 0) {
            ctx.value.moveTo(x, startY + chartHeight)
            ctx.value.lineTo(x, y)
          } else {
            ctx.value.lineTo(x, y)
          }
        })
        
        ctx.value.lineTo(startX + chartWidth, startY + chartHeight)
        ctx.value.closePath()
        ctx.value.fill()
        
        // 绘制线条
        ctx.value.strokeStyle = color
        ctx.value.lineWidth = 2
        ctx.value.beginPath()
        
        dataset.data.forEach((value, index) => {
          const x = startX + (index / (labels.length - 1)) * chartWidth
          const y = startY + chartHeight - ((value - minValue) / valueRange) * chartHeight
          
          if (index === 0) {
            ctx.value.moveTo(x, y)
          } else {
            ctx.value.lineTo(x, y)
          }
        })
        
        ctx.value.stroke()
      })
    }
    
    // 绘制网格
    const drawGrid = (startX, startY, width, height, xLines, yLines) => {
      const options = chartOptions.value
      
      ctx.value.strokeStyle = options.grid.color
      ctx.value.lineWidth = options.grid.lineWidth
      ctx.value.setLineDash([2, 2])
      
      // 垂直网格线
      for (let i = 0; i <= xLines; i++) {
        const x = startX + (i / xLines) * width
        ctx.value.beginPath()
        ctx.value.moveTo(x, startY)
        ctx.value.lineTo(x, startY + height)
        ctx.value.stroke()
      }
      
      // 水平网格线
      for (let i = 0; i <= yLines; i++) {
        const y = startY + (i / yLines) * height
        ctx.value.beginPath()
        ctx.value.moveTo(startX, y)
        ctx.value.lineTo(startX + width, y)
        ctx.value.stroke()
      }
      
      ctx.value.setLineDash([])
    }
    
    // 绘制坐标轴
    const drawAxis = (startX, startY, width, height, labels, minValue, maxValue) => {
      const options = chartOptions.value
      
      ctx.value.strokeStyle = '#333'
      ctx.value.lineWidth = 1
      ctx.value.fillStyle = options.axis.x.color
      ctx.value.font = `${options.axis.x.fontSize}px sans-serif`
      ctx.value.textAlign = 'center'
      ctx.value.textBaseline = 'top'
      
      // X轴标签
      if (options.axis.x.show) {
        labels.forEach((label, index) => {
          const x = startX + (index / (labels.length - 1)) * width
          ctx.value.fillText(label, x, startY + height + 10)
        })
      }
      
      // Y轴标签
      if (options.axis.y.show) {
        ctx.value.fillStyle = options.axis.y.color
        ctx.value.font = `${options.axis.y.fontSize}px sans-serif`
        ctx.value.textAlign = 'right'
        ctx.value.textBaseline = 'middle'
        
        const valueRange = maxValue - minValue
        for (let i = 0; i <= 5; i++) {
          const value = minValue + (valueRange * i / 5)
          const y = startY + height - (i / 5) * height
          ctx.value.fillText(value.toFixed(1), startX - 10, y)
        }
      }
    }
    
    // 更新图例
    const updateLegend = () => {
      if (!props.showLegend) return
      
      const { labels, datasets } = props.data
      const options = chartOptions.value
      
      if (props.type === 'pie' || props.type === 'doughnut') {
        legendData.value = labels.map((label, index) => ({
          name: label,
          color: datasets[0].colors?.[index] || options.colors[index % options.colors.length]
        }))
      } else {
        legendData.value = datasets.map((dataset, index) => ({
          name: dataset.label || `数据${index + 1}`,
          color: dataset.color || options.colors[index % options.colors.length]
        }))
      }
    }
    
    // 触摸事件处理
    const handleTouchStart = (e) => {
      if (!props.enableTooltip) return
      
      const touch = e.touches[0]
      const rect = e.currentTarget.getBoundingClientRect()
      const x = touch.clientX - rect.left
      const y = touch.clientY - rect.top
      
      showTooltipAtPosition(x, y)
    }
    
    const handleTouchMove = (e) => {
      if (!props.enableTooltip) return
      
      const touch = e.touches[0]
      const rect = e.currentTarget.getBoundingClientRect()
      const x = touch.clientX - rect.left
      const y = touch.clientY - rect.top
      
      showTooltipAtPosition(x, y)
    }
    
    const handleTouchEnd = () => {
      setTimeout(() => {
        showTooltip.value = false
      }, 2000)
    }
    
    // 显示工具提示
    const showTooltipAtPosition = (x, y) => {
      // 简化的工具提示逻辑
      const { labels, datasets } = props.data
      
      if (props.type === 'line' || props.type === 'bar' || props.type === 'area') {
        const options = chartOptions.value
        const padding = options.padding
        const chartWidth = props.width - padding.left - padding.right
        
        const relativeX = x - padding.left
        const dataIndex = Math.round((relativeX / chartWidth) * (labels.length - 1))
        
        if (dataIndex >= 0 && dataIndex < labels.length) {
          tooltipData.value = {
            title: labels[dataIndex],
            items: datasets.map((dataset, index) => ({
              label: dataset.label || `数据${index + 1}`,
              value: dataset.data[dataIndex],
              color: dataset.color || options.colors[index % options.colors.length]
            }))
          }
          
          tooltipStyle.value = {
            left: x + 'px',
            top: (y - 60) + 'px'
          }
          
          showTooltip.value = true
        }
      }
    }
    
    // 图例点击事件
    const handleLegendClick = (index) => {
      emit('legendClick', { index, item: legendData.value[index] })
    }
    
    // 监听数据变化
    watch(
      () => [props.data, props.type, props.options],
      () => {
        nextTick(() => {
          drawChart()
        })
      },
      { deep: true }
    )
    
    // 组件挂载
    onMounted(() => {
      nextTick(() => {
        drawChart()
      })
    })
    
    return {
      canvasId,
      showTooltip,
      tooltipData,
      tooltipStyle,
      legendData,
      handleTouchStart,
      handleTouchMove,
      handleTouchEnd,
      handleLegendClick
    }
  }
}
</script>

<style lang="scss" scoped>
.chart-container {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.chart-canvas {
  display: block;
}

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 24rpx;
  margin-top: 32rpx;
  padding: 0 32rpx;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 12rpx;
  padding: 8rpx 16rpx;
  border-radius: 16rpx;
  background-color: #f8f9fa;
  
  &:active {
    background-color: #e9ecef;
  }
}

.legend-color {
  width: 24rpx;
  height: 24rpx;
  border-radius: 50%;
}

.legend-text {
  font-size: 24rpx;
  color: #333;
}

.chart-tooltip {
  position: absolute;
  z-index: 100;
  pointer-events: none;
}

.tooltip-content {
  background-color: rgba(0, 0, 0, 0.8);
  color: #fff;
  padding: 16rpx 24rpx;
  border-radius: 8rpx;
  min-width: 200rpx;
}

.tooltip-title {
  display: block;
  font-size: 26rpx;
  font-weight: 600;
  margin-bottom: 12rpx;
  text-align: center;
}

.tooltip-item {
  display: flex;
  align-items: center;
  gap: 12rpx;
  margin-bottom: 8rpx;
  
  &:last-child {
    margin-bottom: 0;
  }
}

.tooltip-color {
  width: 16rpx;
  height: 16rpx;
  border-radius: 50%;
}

.tooltip-label {
  font-size: 22rpx;
  opacity: 0.9;
}

.tooltip-value {
  font-size: 22rpx;
  font-weight: 600;
  margin-left: auto;
}
</style>