<template>
  <div class="budget-trend-chart">
    <Bar :data="chartData" :options="chartOptions" />
  </div>
</template>

<script setup>
import { computed } from 'vue'
import { Bar } from 'vue-chartjs'
import {
  Chart as ChartJS,
  BarElement,
  CategoryScale,
  Legend,
  LinearScale,
  Tooltip
} from 'chart.js'
import { useAnimationProgress } from '../../composables/useAnimationProgress.js'
import { useThemeColors } from '../../composables/useThemeColors.js'

ChartJS.register(CategoryScale, LinearScale, BarElement, Tooltip, Legend)

const props = defineProps({
  labels: { type: Array, required: true },
  budget: { type: Array, required: true },
  used: { type: Array, required: true },
  occupied: { type: Array, default: () => [] },
  available: { type: Array, default: () => [] }
})

const progress = useAnimationProgress([
  () => props.labels,
  () => props.budget,
  () => props.used,
  () => props.occupied,
  () => props.available
], 1000)
const themeColors = useThemeColors()
const prefersReducedMotion = () =>
  typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches

const currency = (value) =>
  Number(value || 0).toLocaleString('zh-CN', {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  })

const percent = (value, total) => {
  const denominator = Number(total || 0)
  if (!denominator) return 0
  return Number(((Number(value || 0) / denominator) * 100).toFixed(2))
}

const percentSeries = (series) =>
  props.budget.map((total, index) => percent(series[index], total))

const scaleSeries = (series) =>
  series.map((value) => Number((Number(value || 0) * progress.value).toFixed(2)))

const usedPercent = computed(() => percentSeries(props.used))
const occupiedPercent = computed(() => percentSeries(props.occupied))
const availablePercent = computed(() =>
  props.budget.map((total, index) => {
    const usedValue = Number(props.used[index] || 0)
    const occupiedValue = Number(props.occupied[index] || 0)
    return percent(Math.max(Number(total || 0) - usedValue - occupiedValue, 0), total)
  })
)

const yAxisMax = computed(() => {
  const maxUsage = Math.max(
    100,
    ...usedPercent.value.map((value, index) => value + Number(occupiedPercent.value[index] || 0))
  )
  return Math.ceil(maxUsage / 20) * 20
})

const chartData = computed(() => ({
  labels: props.labels,
  datasets: [
    {
      label: '已使用',
      data: scaleSeries(usedPercent.value),
      backgroundColor: themeColors.value.chartPrimary,
      borderRadius: 4,
      borderSkipped: false,
      stack: 'budgetUsage',
      amounts: props.used
    },
    {
      label: '已占用',
      data: scaleSeries(occupiedPercent.value),
      backgroundColor: themeColors.value.warning,
      borderRadius: 4,
      borderSkipped: false,
      stack: 'budgetUsage',
      amounts: props.occupied
    },
    {
      label: '剩余可用',
      data: scaleSeries(availablePercent.value),
      backgroundColor: '#e5edf3',
      borderRadius: 4,
      borderSkipped: false,
      stack: 'budgetUsage',
      amounts: props.available
    }
  ]
}))

const chartOptions = computed(() => ({
  responsive: true,
  maintainAspectRatio: false,
  interaction: {
    mode: 'index',
    intersect: false
  },
  animation: {
    duration: prefersReducedMotion() ? 0 : 760,
    easing: 'easeOutQuart'
  },
  plugins: {
    legend: {
      display: false
    },
    tooltip: {
      backgroundColor: '#ffffff',
      borderColor: '#e2e8f0',
      borderWidth: 1,
      bodyColor: '#475569',
      titleColor: '#0f172a',
      cornerRadius: 4,
      padding: 12,
      displayColors: true,
      callbacks: {
        label(context) {
          const value = Number(context.parsed.y || 0)
          const amount = Number(context.dataset.amounts?.[context.dataIndex] || 0)
          return `${context.dataset.label}: ${value.toFixed(2)}%（¥${currency(amount)}）`
        },
        afterBody(items) {
          const index = items[0]?.dataIndex ?? 0
          return `预算总额: ¥${currency(props.budget[index])}`
        }
      }
    }
  },
  scales: {
    x: {
      grid: { display: false },
      ticks: {
        color: '#64748b',
        font: { size: 12 }
      },
      border: { display: false }
    },
    y: {
      beginAtZero: true,
      max: yAxisMax.value,
      stacked: true,
      grid: {
        color: '#edf2f7',
        drawTicks: false
      },
      border: { display: false },
      ticks: {
        color: '#64748b',
        font: { size: 12 },
        stepSize: 20,
        callback(value) {
          return `${Number(value)}%`
        }
      }
    }
  },
  datasets: {
    bar: {
      categoryPercentage: 0.58,
      barPercentage: 0.72
    }
  }
}))
</script>

<style scoped>
.budget-trend-chart {
  position: relative;
  width: 100%;
  height: 220px;
}
</style>
