<template>
  <section class="traffic-3">
    <div class="chart-legend">
      <span class="legend-item legend-item--actual">实际</span>
      <span class="legend-item legend-item--compare">对比日(2026-03-05)</span>
      <span class="legend-item legend-item--history">历史峰值</span>
      <span class="legend-unit">单位：万人次</span>
    </div>

    <div class="line-chart-grid">
      <article v-for="(item, index) in chartCards" :key="item.lineId" class="line-chart-card">
        <div class="line-chart-header">
          <span class="line-badge" :style="getLineStyle(item.lineId)">{{ item.lineId }}</span>
          <span class="line-title">累计<br>客流</span>
          <div class="total-digits">
            <span v-for="(_, digitIndex) in targetTotals[index]" :key="`${item.lineId}-${digitIndex}`" class="digit-box">
              <span
                :ref="el => setDigitRef(el, index, digitIndex)"
                class="digit-odometer"
              >0</span>
            </span>
          </div>
        </div>

        <v-chart class="line-chart" :option="item.option" autoresize />
      </article>
    </div>
  </section>
</template>

<script setup>
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import VChart from 'vue-echarts'
import * as echarts from 'echarts'
import Odometer from 'odometer'
import 'odometer/themes/odometer-theme-default.css'
import { METRO_LINES } from '@/utils/const'

const hours = ['5', '7', '9', '11', '13', '15', '17', '19', '21', '23']
const pointGlowSymbol = 'image:///imgs/traffic/4-item.png'

const lineCards = ref([
  {
    lineId: 3,
    total: '2746782',
    actual: [2600, 4700, 2400, 3900, 2300, 4100, 2600, 3300, 1700, 2200],
    compare: [4850, 4550, 4650, 4300, 4300, 4550, 4700, 3900, 3900, 3000],
    history: [5000, 4600, 4700, 4200, 4200, 4450, 4600, 4300, 3900, 3600]
  },
  {
    lineId: 4,
    total: '2746782',
    actual: [700, 950, 1550, 4200, 1700, 1350, 1600, 1550, 2500, 1400],
    compare: [1150, 1450, 2200, 3900, 2500, 1550, 1700, 1650, 2950, 2050],
    history: [1350, 2200, 3100, 4450, 3000, 2650, 2550, 2750, 4200, 4550]
  },
  {
    lineId: 7,
    total: '2746782',
    actual: [2900, 3300, 5000, 2300, 2000, 1900, 2600, 4050, 1700, 1700],
    compare: [3200, 3700, 5200, 2500, 2400, 2500, 3100, 4700, 2400, 2400],
    history: [3300, 4100, 5300, 2700, 2650, 2900, 3500, 4950, 3300, 2700]
  },
  {
    lineId: 15,
    total: '2746782',
    actual: [3000, 3600, 4550, 2400, 3900, 2200, 3400, 4050, 2800, 3300],
    compare: [4700, 4300, 4500, 4100, 4100, 4300, 4400, 4550, 4000, 3900],
    history: [4850, 4350, 4550, 4100, 4100, 4300, 4450, 4500, 3950, 3600]
  }
]) 


setTimeout(() => {
  lineCards.value[0].total = '8846081'
}, 8000);

const chartCards = computed(() => {
  return lineCards.value.map(item => ({
    ...item,
    option: createChartOption(item)
  }))
})

const targetTotals = computed(() => lineCards.value.map(item => item.total.split('')))
const digitEls = []
const odometerInstances = []

const setDigitRef = (el, cardIndex, digitIndex) => {
  if (!el) {
    return
  }

  digitEls[cardIndex] ||= []
  digitEls[cardIndex][digitIndex] = el
}

const initOdometers = () => {
  targetTotals.value.forEach((digits, cardIndex) => {
    odometerInstances[cardIndex] ||= []

    digits.forEach((_, digitIndex) => {
      const el = digitEls[cardIndex]?.[digitIndex]

      if (!el || odometerInstances[cardIndex][digitIndex]) {
        return
      }

      odometerInstances[cardIndex][digitIndex] = new Odometer({
        el,
        value: 0,
        format: 'd',
        duration: 1200,
        theme: 'default'
      })
    })
  })
}

const updateOdometers = () => {
  targetTotals.value.forEach((digits, cardIndex) => {
    digits.forEach((digit, digitIndex) => {
      odometerInstances[cardIndex]?.[digitIndex]?.update(Number(digit))
    })
  })
}

watch(targetTotals, async () => {
  await nextTick()
  initOdometers()
  updateOdometers()
})

onMounted(async () => {
  await nextTick()
  initOdometers()
  requestAnimationFrame(updateOdometers)
})

const getLineStyle = lineId => {
  const theme = METRO_LINES[lineId] || {
    bg: '#2bd5ff',
    color: '#00194a'
  }

  return {
    backgroundColor: theme.bg,
    color: theme.color
  }
}

const createChartOption = item => ({
  backgroundColor: 'transparent',
  animationDuration: 900,
  grid: {
    left: 6,
    right: 34,
    top: 16,
    bottom: 14,
    containLabel: true
  },
  xAxis: {
    type: 'category',
    boundaryGap: false,
    data: hours,
    axisLine: {
      lineStyle: {
        color: 'rgba(167, 205, 255, 0.45)'
      }
    },
    axisTick: {
      show: false
    },
    axisLabel: {
      color: 'rgba(226, 239, 255, 0.96)',
      fontSize: 14,
      fontWeight: 600,
      margin: 10
    },
    splitLine: {
      show: false
    }
  },
  yAxis: {
    type: 'value',
    min: 0,
    max: 5000,
    interval: 1000,
    axisLine: {
      show: false
    },
    axisTick: {
      show: false
    },
    axisLabel: {
      color: 'rgba(226, 239, 255, 0.96)',
      fontSize: 13,
      fontWeight: 600,
      margin: 10
    },
    splitLine: {
      lineStyle: {
        color: 'rgba(219, 235, 255, 0.32)',
        type: 'dashed',
        width: 1.5
      }
    }
  },
  series: [
    {
      type: 'scatter',
      data: hours.map((hour, index) => [hour, item.actual[index]]),
      symbol: pointGlowSymbol,
      symbolSize: [38, 88],
      symbolOffset: [3, 0],
      symbolKeepAspect: false,
      silent: true,
      z: 3,
      tooltip: {
        show: false
      }
    },
    {
      name: '实际',
      type: 'line',
      data: item.actual,
      smooth: false,
      symbol: 'circle',
      symbolSize: 5,
      z: 5,
      lineStyle: {
        color: '#20cfff',
        width: 3,
        shadowBlur: 8,
        shadowColor: 'rgba(32, 207, 255, 0.55)'
      },
      itemStyle: {
        color: '#dffbff',
        borderColor: '#20cfff',
        borderWidth: 2
      },
      areaStyle: {
        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
          { offset: 0, color: 'rgba(27, 218, 255, 0.86)' },
          { offset: 0.58, color: 'rgba(21, 144, 226, 0.48)' },
          { offset: 1, color: 'rgba(13, 74, 166, 0.16)' }
        ])
      }
    },
    {
      name: '对比日(2026-03-05)',
      type: 'line',
      data: item.compare,
      smooth: false,
      symbol: 'none',
      z: 3,
      lineStyle: {
        color: '#f5c400',
        width: 2
      }
    },
    {
      name: '历史峰值',
      type: 'line',
      data: item.history,
      smooth: false,
      symbol: 'none',
      z: 3,
      lineStyle: {
        color: '#ff1d1d',
        width: 2
      }
    }
  ],
  tooltip: {
    trigger: 'axis',
    backgroundColor: 'rgba(0, 18, 55, 0.92)',
    borderColor: 'rgba(31, 205, 255, 0.45)',
    textStyle: {
      color: '#ffffff',
      fontSize: 12
    }
  }
})
</script>

<style lang="scss" scoped>
  .traffic-3 {
    position: absolute;
    left: 1689px;
    top: 128px;
    width: 1250px;
    height: 895px;
    background: url('/imgs/traffic/3-bg.png') no-repeat center center;
    background-size: cover;

    .chart-legend {
      position: absolute;
      top: 64px;
      left: 32px;
      display: flex;
      align-items: center;
      gap: 20px;
      color: #ffffff;
      font-size: 18px;
      font-weight: 500;
      line-height: 1;
    }

    .legend-item {
      position: relative;
      padding-left: 18px;

      &::before {
        content: '';
        position: absolute;
        top: 50%;
        left: 0;
        width: 12px;
        height: 12px;
        border-radius: 50%;
        transform: translateY(-50%);
      }

      &--actual::before {
        background: #20d8ff;
      }

      &--compare::before {
        background: #f5c400;
      }

      &--history::before {
        background: #ff1d1d;
      }
    }

    .legend-unit {
      margin-left: -12px;
    }

    .line-chart-grid {
      position: absolute;
      top: 96px;
      right: 23px;
      bottom: 22px;
      left: 23px;
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      grid-template-rows: repeat(2, minmax(0, 1fr));
      gap: 27px 26px;
    }

    .line-chart-card {
      position: relative;
      overflow: hidden;
      background: rgba(27, 83, 165, 0.25);

    }

    .line-chart-header {
      position: absolute;
      top: 36px;
      left: 20px;
      right: 22px;
      z-index: 2;
      display: flex;
      align-items: center;
    }

    .line-badge {
      width: 39px;
      height: 39px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      border-radius: 6px;
      font-size: 30px;
      font-weight: 600;
      line-height: 1;
    }

    .line-title {
      margin-left: 21px;
      color: #ffffff;
      font-size: 18px;
      font-weight: 500;
  line-height: normal;
    }

    .total-digits {
      display: flex;
      align-items: center;
      gap: 15px;
      margin-left: 47px;
    }

    .digit-box {
      width: 39px;
      height: 44px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
      color: #ffffff;
      font-size: 28px;
      font-weight: 600;
      line-height: 1;
      background: url('/imgs/traffic/3-item.png') no-repeat center center;
      background-size: contain;
    }

    .digit-odometer {
      width: 39px;
      height: 44px;
      display: block;
      color: #ffffff;
      font-family: inherit;
      font-size: 28px;
      font-weight: 600;
      line-height: 44px;
      text-align: center;
    }

    .digit-odometer :deep(.odometer-digit),
    .digit-odometer :deep(.odometer-digit-spacer) {
      width: 39px;
      height: 44px;
      line-height: 44px;
    }

    .digit-odometer :deep(.odometer-digit-inner) {
      width: 39px;
      height: 44px;
      line-height: 44px;
    }

    .digit-odometer :deep(.odometer-value) {
      width: 39px;
      height: 44px;
      line-height: 44px;
      text-align: center;
    }

    .line-chart {
      position: absolute;
      right: 0;
      bottom: 14px;
      left: 10px;
      height: 238px;
    }
  }
</style>
