<template>
  <div class="token-usage-page">
    <div class="usage-shell">
      <!-- <div class="page-header">
        <div>
          <div class="title-line">
            <span class="title-icon">
              <i class="el-icon-data-line"></i>
            </span>
            <h2>Token用量</h2> 
          </div>
          <p>查看模型调用 Token 消耗、调用次数和费用趋势。</p>
        </div>
        <div class="header-actions">
          <span class="range-badge">{{ filterTimeText }}</span>
          <el-button size="small" icon="el-icon-refresh" class="refresh-btn" :loading="loading" @click="getTokenList">刷新</el-button>
        </div>
      </div> -->

      <div class="stat-row">
        <div v-for="item in statCards" :key="item.label" class="stat-card" :class="item.type">
          <div class="stat-card-head">
            <span>{{ item.label }}</span>
            <i :class="item.icon"></i>
          </div>
          <strong>{{ item.value }}</strong>
          <em>{{ item.desc }}</em>
        </div>
      </div>

      <div class="usage-dashboard">
        <div class="dashboard-card token-ratio-card">
          <div class="dashboard-title">
            <h3>Token 使用概览</h3>
            <span>{{ rangeLabel }}</span>
          </div>
          <div class="token-total">{{ formatNumber(summary.total_tokens) }}</div>
          <p>总 Token 消耗</p>
          <div ref="tokenRatioChart" class="chart-box token-ratio-chart"></div>
        </div>

        <div class="dashboard-card model-rank-card">
          <div class="dashboard-title">
            <h3>模型消耗排行</h3>
            <span>当前页数据</span>
          </div>
          <div ref="modelRankChart" class="chart-box model-rank-chart"></div>
        </div>
      </div>

      <div class="content-card">
        <div class="card-header">
          <div>
            <h3>用量明细</h3>
            <p>按模型维度统计 Token 输入、输出与费用。</p>
          </div>
          <div class="filter-actions">
            <el-select v-model="query.range" size="small" placeholder="快捷范围" @change="handleRangeChange">
              <el-option label="最近1小时" value="hour"></el-option>
              <el-option label="今天" value="day"></el-option>
              <el-option label="最近一周" value="week"></el-option>
            </el-select>
            <el-input
              v-model="query.model"
              size="small"
              clearable
              placeholder="搜索模型"
              @keyup.enter.native="handleSearch"
              @clear="handleSearch"
            ></el-input>
            <el-date-picker
              v-model="dateRange"
              type="daterange" 
              size="small"
              value-format="yyyy-MM-dd"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              @change="handleDateChange"
            ></el-date-picker>
          </div>
        </div>

        <el-table v-loading="loading" :data="usageList" class="usage-table" style="width: 100%">
          <el-table-column prop="model" label="模型名称" min-width="180" show-overflow-tooltip></el-table-column>
          <el-table-column prop="request_count" label="调用次数" width="120"></el-table-column>
          <el-table-column prop="prompt_tokens" label="输入Token" min-width="140"></el-table-column>
          <el-table-column prop="completion_tokens" label="输出Token" min-width="140"></el-table-column>
          <el-table-column prop="total_tokens" label="总Token" min-width="140"></el-table-column>
          <el-table-column prop="amount" label="预估费用" width="130">
            <template slot-scope="scope">¥ {{ formatAmount(scope.row.amount) }}</template>
          </el-table-column>
          <el-table-column prop="usage_time" label="使用时间" min-width="170" show-overflow-tooltip></el-table-column>
        </el-table>

        <div class="table-pagination">
          <el-pagination
            background
            layout="total, sizes, prev, pager, next, jumper"
            :total="total"
            :current-page="query.current_page"
            :page-size="query.page_size"
            :page-sizes="[10, 20, 50, 100]"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
          ></el-pagination>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import echarts from 'echarts'
import { reqTokenUsage } from '@/api/model/model'

export default {
  name: 'TokenUsage',
  data() {
    return {
      loading: false,
      dateRange: [],
      summary: {
        request_count: 0,
        prompt_tokens: 0,
        completion_tokens: 0,
        total_tokens: 0,
        amount: 0
      },
      statCards: [
        { label: '总消耗 Token', value: '0', desc: '当前筛选范围', type: 'primary', icon: 'el-icon-coin' },
        { label: '调用次数', value: '0', desc: '当前筛选范围', type: 'success', icon: 'el-icon-s-promotion' },
        { label: '预估费用', value: '¥ 0.00', desc: '按当前单价估算', type: 'warning', icon: 'el-icon-wallet' },
        { label: '输入/输出 Token', value: '0 / 0', desc: 'Prompt / Completion', type: 'purple', icon: 'el-icon-pie-chart' }
      ],
      usageList: [],
      total: 0,
      tokenRatioChart: null,
      modelRankChart: null,
      query:{
        userid:this.getCurrentUserId(),
        range:'week',
        start_time:'',
        end_time:'',
        model: '',
        current_page:1,
        page_size:10
      }
    }
  },
  computed: {
    rangeLabel() {
      const labelMap = {
        hour: '最近1小时',
        day: '今天',
        week: '最近一周'
      }
      return labelMap[this.query.range] || '当前范围'
    },
    filterTimeText() {
      if (this.query.start_time && this.query.end_time) {
        return `${this.query.start_time} 至 ${this.query.end_time}`
      }
      return this.rangeLabel
    },
    modelUsageRank() {
      const maxTokens = Math.max(...this.usageList.map(item => Number(item.total_tokens || 0)), 0)
      return this.usageList
        .map(item => ({
          model: item.model,
          total_tokens: Number(item.total_tokens || 0),
          percent: maxTokens ? Math.round((Number(item.total_tokens || 0) / maxTokens) * 100) : 0
        }))
        .sort((a, b) => b.total_tokens - a.total_tokens)
        .slice(0, 5)
    }
  },
  created() {
    this.getTokenList()
  },
  mounted() {
    this.initCharts()
    this.renderCharts()
    window.addEventListener('resize', this.resizeCharts)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.resizeCharts)
    if (this.tokenRatioChart) {
      this.tokenRatioChart.dispose()
      this.tokenRatioChart = null
    }
    if (this.modelRankChart) {
      this.modelRankChart.dispose()
      this.modelRankChart = null
    }
  },
  methods: {
    getCurrentUserId() {
      return sessionStorage.getItem('userId') || localStorage.getItem('userId') || ''
    },
    handleDateChange(value) {
      if (value && value.length === 2) {
        this.query.start_time = value[0]
        this.query.end_time = value[1]
      } else {
        this.query.start_time = ''
        this.query.end_time = ''
      }
      this.query.current_page = 1
      this.getTokenList()
    },
    handleRangeChange() {
      this.query.current_page = 1
      this.getTokenList()
    },
    handleSearch() {
      this.query.current_page = 1
      this.getTokenList()
    },
    async getTokenList() {
      this.query.userid = this.getCurrentUserId()
      this.loading = true
      try {
        const res = await reqTokenUsage(this.query)
        if(res.status === true) {
          const data = res.data || {}
          this.summary = {
            ...this.summary,
            ...(data.summary || {})
          }
          this.updateStatCards()
          this.usageList = data.items || []
          this.total = Number(data.total_count || 0)
          this.query.current_page = Number(data.current_page || this.query.current_page)
          this.query.page_size = Number(data.page_size || this.query.page_size)
          this.$nextTick(this.renderCharts)
        }
        console.log('token用量',res);
      } finally {
        this.loading = false
      }
    },
    updateStatCards() {
      this.statCards = [
        { label: '总消耗 Token', value: this.formatNumber(this.summary.total_tokens), desc: '当前筛选范围', type: 'primary', icon: 'el-icon-coin' },
        { label: '调用次数', value: this.formatNumber(this.summary.request_count), desc: '当前筛选范围', type: 'success', icon: 'el-icon-s-promotion' },
        { label: '预估费用', value: `¥ ${this.formatAmount(this.summary.amount)}`, desc: '按当前单价估算', type: 'warning', icon: 'el-icon-wallet' },
        { label: '输入/输出 Token', value: `${this.formatNumber(this.summary.prompt_tokens)} / ${this.formatNumber(this.summary.completion_tokens)}`, desc: 'Prompt / Completion', type: 'purple', icon: 'el-icon-pie-chart' }
      ]
    },
    formatNumber(value) {
      return Number(value || 0).toLocaleString()
    },
    formatAmount(value) {
      return Number(value || 0).toFixed(6).replace(/0+$/, '').replace(/\.$/, '.00')
    },
    initCharts() {
      if (this.$refs.tokenRatioChart && !this.tokenRatioChart) {
        this.tokenRatioChart = echarts.init(this.$refs.tokenRatioChart)
      }
      if (this.$refs.modelRankChart && !this.modelRankChart) {
        this.modelRankChart = echarts.init(this.$refs.modelRankChart)
      }
    },
    renderCharts() {
      if (!this.$refs.tokenRatioChart || !this.$refs.modelRankChart) return
      this.initCharts()
      this.renderTokenRatioChart()
      this.renderModelRankChart()
    },
    renderTokenRatioChart() {
      if (!this.tokenRatioChart) return
      const promptTokens = Number(this.summary.prompt_tokens || 0)
      const completionTokens = Number(this.summary.completion_tokens || 0)
      const hasData = promptTokens || completionTokens
      this.tokenRatioChart.setOption({
        tooltip: {
          trigger: 'item',
          formatter: '{b}: {c} Token ({d}%)'
        },
        legend: {
          bottom: 0,
          icon: 'circle',
          textStyle: {
            color: '#606266'
          }
        },
        color: ['#409eff', '#67c23a'],
        series: [
          {
            name: 'Token占比',
            type: 'pie',
            radius: ['52%', '72%'],
            center: ['50%', '44%'],
            avoidLabelOverlap: true,
            label: {
              formatter: '{b}\n{d}%'
            },
            data: hasData
              ? [
                { name: '输入Token', value: promptTokens },
                { name: '输出Token', value: completionTokens }
              ]
              : [{ name: '暂无数据', value: 1 }],
            itemStyle: {
              borderColor: '#fff',
              borderWidth: 3
            }
          }
        ]
      })
    },
    renderModelRankChart() {
      if (!this.modelRankChart) return
      const rankList = this.modelUsageRank.slice().reverse()
      this.modelRankChart.setOption({
        grid: {
          top: 12,
          right: 24,
          bottom: 20,
          left: 92
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          },
          formatter: params => {
            const item = params && params[0]
            return item ? `${item.name}<br/>${this.formatNumber(item.value)} Token` : ''
          }
        },
        xAxis: {
          type: 'value',
          axisLine: { show: false },
          axisTick: { show: false },
          splitLine: {
            lineStyle: {
              color: '#edf1f7'
            }
          }
        },
        yAxis: {
          type: 'category',
          data: rankList.map(item => item.model || '-'),
          axisLine: { show: false },
          axisTick: { show: false },
          axisLabel: {
            color: '#606266',
            width: 82,
            overflow: 'truncate'
          }
        },
        series: [
          {
            name: 'Token消耗',
            type: 'bar',
            barWidth: 12,
            data: rankList.map(item => item.total_tokens),
            itemStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                { offset: 0, color: '#a78bfa' },
                { offset: 1, color: '#7c3aed' }
              ]),
              barBorderRadius: [0, 8, 8, 0]
            },
            label: {
              show: true,
              position: 'right',
              color: '#344054',
              formatter: params => this.formatNumber(params.value)
            }
          }
        ]
      })
    },
    resizeCharts() {
      if (this.tokenRatioChart) this.tokenRatioChart.resize()
      if (this.modelRankChart) this.modelRankChart.resize()
    },
    handleSizeChange(size) {
      this.query.page_size = size
      this.query.current_page = 1
      this.getTokenList()
    },
    handleCurrentChange(page) {
      this.query.current_page = page
      this.getTokenList()
    },
    handleReset() {
      this.dateRange = []
      this.query = {
        userid: this.getCurrentUserId(),
        range: 'week',
        start_time: '',
        end_time: '',
        model: '',
        current_page: 1,
        page_size: 10
      }
      this.getTokenList()
    }
    }
}
</script>

<style lang="less" scoped>
.token-usage-page {
  min-height: 100vh;
  padding: 24px;
  background:
    radial-gradient(circle at top left, rgba(64, 158, 255, 0.16), transparent 34%),
    linear-gradient(180deg, #f3f7ff 0%, #f7f9fc 48%, #ffffff 100%);
}

.usage-shell {
  min-height: calc(100vh - 48px);
  padding: 24px;
  background: rgba(255, 255, 255, 0.92);
  border: 1px solid #edf1f7;
  border-radius: 18px;
  box-shadow: 0 12px 30px rgba(31, 45, 61, 0.06);
}

.page-header,
.card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
}

.page-header {
  align-items: center;
  padding: 20px 22px;
  margin-bottom: 20px;
  overflow: hidden;
  color: #ffffff;
  background: linear-gradient(135deg, #1e6fff 0%, #409eff 48%, #7c3aed 100%);
  border-radius: 18px;
  box-shadow: 0 14px 34px rgba(64, 158, 255, 0.22);

  p {
    color: rgba(255, 255, 255, 0.82);
  }
}

.title-line {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;

  h2 {
    margin: 0;
    color: #ffffff;
    font-size: 24px;
  }
}

.title-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  color: #ffffff;
  font-size: 18px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 12px;
}

.page-header p,
.card-header p {
  margin: 0;
  color: #909399;
  font-size: 13px;
}

.refresh-btn {
  color: #1e6fff;
  border: none;
  border-radius: 10px;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.range-badge {
  padding: 7px 12px;
  color: #ffffff;
  font-size: 12px;
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 999px;
}

.stat-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin-bottom: 20px;
}

.stat-card {
  position: relative;
  overflow: hidden;
  padding: 20px;
  border-radius: 16px;
  border: 1px solid #edf1f7;
  background: #ffffff;
  box-shadow: 0 8px 24px rgba(31, 45, 61, 0.04);
  transition: transform 0.2s ease, box-shadow 0.2s ease;

  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 12px 28px rgba(31, 45, 61, 0.08);
  }

  span,
  em {
    display: block;
    color: #909399;
    font-style: normal;
    font-size: 13px;
  }

  strong {
    display: block;
    margin: 10px 0 8px;
    color: #1f2d3d;
    font-size: 26px;
  }

  &:before {
    position: absolute;
    top: 0;
    right: 0;
    width: 86px;
    height: 86px;
    content: '';
    background: rgba(255, 255, 255, 0.52);
    border-radius: 0 0 0 86px;
  }

  &.primary {
    background: linear-gradient(135deg, #eef5ff 0%, #ffffff 100%);
  }

  &.success {
    background: linear-gradient(135deg, #f0fdf4 0%, #ffffff 100%);
  }

  &.warning {
    background: linear-gradient(135deg, #fff7ed 0%, #ffffff 100%);
  }

  &.purple {
    background: linear-gradient(135deg, #f5f3ff 0%, #ffffff 100%);
  }
}

.stat-card-head {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;

  i {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    color: #409eff;
    font-size: 18px;
    background: rgba(64, 158, 255, 0.12);
    border-radius: 12px;
  }
}

.usage-dashboard {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
  gap: 16px;
  margin-bottom: 20px;
}

.dashboard-card {
  padding: 22px;
  border: 1px solid #edf1f7;
  border-radius: 16px;
  background: #ffffff;
  box-shadow: 0 10px 26px rgba(31, 45, 61, 0.05);
}

.dashboard-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;

  h3 {
    margin: 0;
    color: #1f2d3d;
    font-size: 16px;
  }

  span {
    color: #909399;
    font-size: 12px;
  }
}

.token-total {
  color: #1f2d3d;
  font-size: 34px;
  font-weight: 700;
  line-height: 1.2;
}

.token-ratio-card {
  p {
    margin: 6px 0 18px;
    color: #909399;
    font-size: 13px;
  }
}

.chart-box {
  width: 100%;
  height: 240px;
}

.model-rank-chart {
  height: 300px;
}

.ratio-list,
.rank-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.ratio-label,
.rank-info {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
  color: #606266;
  font-size: 13px;

  strong {
    color: #1f2d3d;
    font-weight: 700;
  }
}

.content-card {
  padding: 22px;
  border: 1px solid #edf1f7;
  border-radius: 16px;
  background: #ffffff;
  box-shadow: 0 10px 26px rgba(31, 45, 61, 0.05);
}

.card-header {
  margin-bottom: 18px;

  h3 {
    margin: 0 0 8px;
    color: #1f2d3d;
  }
}

.filter-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  background: #f6f8fb;
  border: 1px solid #edf1f7;
  border-radius: 12px;

  /deep/ .el-select {
    width: 110px;
  }

  /deep/ .el-input {
    width: 160px;
  }

  /deep/ .el-input__inner {
    border-color: transparent;
  }
}

.usage-table {
  border-radius: 12px;
  overflow: hidden;

  /deep/ .el-table__header th {
    color: #475467;
    font-weight: 700;
    background: #f8fafc;
  }

  /deep/ .el-table__row:hover > td {
    background: #f6faff;
  }
}

.table-pagination {
  display: flex;
  justify-content: flex-end;
  margin-top: 16px;
}

@media (max-width: 1100px) {
  .stat-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .usage-dashboard {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 700px) {
  .stat-row {
    grid-template-columns: 1fr;
  }

  .page-header,
  .card-header {
    flex-direction: column;
  }

  .filter-actions {
    align-items: flex-start;
    flex-direction: column;
    width: 100%;

    /deep/ .el-date-editor {
      width: 100%;
    }
  }
}
</style>
