<template>
  <div class="usage-view">
    <a-page-header
      title="用量仪表盘"
      sub-title="查看 Token、成本与请求用量统计"
      class="usage-view__header"
    >
      <template #extra>
        <a-space :size="8">
          <a-button @click="loadAll" :loading="loading">刷新</a-button>
          <a-dropdown @click.prevent>
            <a-button type="primary">
              <DownloadOutlined />
              导出报表
              <DownOutlined />
            </a-button>
            <template #overlay>
              <a-menu @click="handleExport">
                <a-menu-item key="csv">导出 CSV</a-menu-item>
                <a-menu-item key="json">导出 JSON</a-menu-item>
              </a-menu>
            </template>
          </a-dropdown>
        </a-space>
      </template>
    </a-page-header>

    <a-card class="usage-view__filters" :bordered="false">
      <a-form layout="inline">
        <a-form-item label="时间范围">
          <a-range-picker
            v-model:value="dateRange"
            :allow-clear="true"
            :presets="rangePresets"
            format="YYYY-MM-DD"
            @change="loadAll"
          />
        </a-form-item>
        <a-form-item label="部门">
          <a-select
            v-model:value="departmentId"
            placeholder="全部部门"
            allow-clear
            style="width: 220px"
            :options="deptOptions"
            @change="loadAll"
          />
        </a-form-item>
      </a-form>
    </a-card>

    <a-spin :spinning="loading">
      <a-row :gutter="16" class="usage-view__stats">
        <a-col :xs="24" :sm="8">
          <a-card>
            <a-statistic
              title="总 Token 用量"
              :value="summary?.total_tokens ?? 0"
              :value-style="{ color: '#1677ff' }"
            />
            <div class="usage-view__stat-hint">累计输入 + 输出 Token</div>
          </a-card>
        </a-col>
        <a-col :xs="24" :sm="8">
          <a-card>
            <a-statistic
              title="总成本 (USD)"
              :value="summary?.total_cost ?? 0"
              :precision="4"
              :value-style="{ color: '#52c41a' }"
            />
            <div class="usage-view__stat-hint">按模型计费汇总</div>
          </a-card>
        </a-col>
        <a-col :xs="24" :sm="8">
          <a-card>
            <a-statistic
              title="总请求数"
              :value="summary?.total_requests ?? 0"
              :value-style="{ color: '#722ed1' }"
            />
            <div class="usage-view__stat-hint">LLM 调用次数</div>
          </a-card>
        </a-col>
      </a-row>

      <a-row :gutter="16" class="usage-view__tables">
        <a-col :xs="24" :lg="12">
          <a-card title="按模型分布" class="usage-view__table-card">
            <a-empty
              v-if="byModel.length === 0"
              :image="Empty.PRESENTED_IMAGE_SIMPLE"
              description="暂无数据"
            />
            <a-table
              v-else
              :columns="modelColumns"
              :data-source="byModel"
              :row-key="(record: IUsageByModel) => record.model"
              :pagination="false"
              size="middle"
            >
              <template #bodyCell="{ column, record }: { column: TableColumnType<IUsageByModel>; record: IUsageByModel }">
                <template v-if="column.key === 'cost'">
                  {{ formatCost(record.cost) }}
                </template>
                <template v-else-if="column.key === 'tokens'">
                  {{ formatNumber(record.tokens) }}
                </template>
              </template>
            </a-table>
          </a-card>
        </a-col>

        <a-col :xs="24" :lg="12">
          <a-card title="Top 用户" class="usage-view__table-card">
            <a-empty
              v-if="topUsers.length === 0"
              :image="Empty.PRESENTED_IMAGE_SIMPLE"
              description="暂无数据"
            />
            <a-table
              v-else
              :columns="userColumns"
              :data-source="topUsers"
              :row-key="(record: IUsageTopUser) => record.user_id"
              :pagination="{ pageSize: 10, showSizeChanger: false }"
              size="middle"
            >
              <template #bodyCell="{ column, record }: { column: TableColumnType<IUsageTopUser>; record: IUsageTopUser }">
                <template v-if="column.key === 'cost'">
                  {{ formatCost(record.cost) }}
                </template>
                <template v-else-if="column.key === 'tokens'">
                  {{ formatNumber(record.tokens) }}
                </template>
              </template>
            </a-table>
          </a-card>
        </a-col>
      </a-row>

      <a-card title="按部门分布" class="usage-view__dept-card">
        <a-empty
          v-if="deptRows.length === 0"
          :image="Empty.PRESENTED_IMAGE_SIMPLE"
          description="暂无数据"
        />
        <a-table
          v-else
          :columns="deptColumns"
          :data-source="deptRows"
          :row-key="(record: IDeptUsageRow) => record.department_id"
          :pagination="false"
          size="middle"
        >
          <template #bodyCell="{ column, record }: { column: TableColumnType<IDeptUsageRow>; record: IDeptUsageRow }">
            <template v-if="column.key === 'cost'">
              {{ formatCost(record.cost) }}
            </template>
            <template v-else-if="column.key === 'tokens'">
              {{ formatNumber(record.tokens) }}
            </template>
          </template>
        </a-table>
      </a-card>
    </a-spin>
  </div>
</template>

<script setup lang="ts">
/**
 * Usage dashboard — summary cards + by-model / top-users / by-department
 * breakdown tables.
 *
 * Uses simple tables/cards instead of chart libraries (per U9 spec).
 * The export button calls ``adminApi.exportUsage()`` which returns the
 * raw CSV/JSON text from the server; we wrap it in a Blob and trigger
 * a browser download.
 */
import { ref, computed, onMounted } from 'vue'
import dayjs, { type Dayjs } from 'dayjs'
import { message, Empty } from 'ant-design-vue'
import type { TableColumnType } from 'ant-design-vue'
import { DownloadOutlined, DownOutlined } from '@ant-design/icons-vue'
import {
  adminApi,
  type IDepartment,
  type IUsageSummary,
  type IUsageByModel,
  type IUsageTopUser,
} from '@/api/admin'

interface ISelectOption {
  label: string
  value: string
}

/** Per-bucket usage metric (matches ``IUsageSummary.by_*`` value shape). */
interface IUsageMetric {
  total_tokens: number
  total_cost: number
  count: number
}

/** Flattened per-department usage row (derived from ``IUsageSummary.by_department``). */
interface IDeptUsageRow {
  department_id: string
  tokens: number
  cost: number
  requests: number
}

interface IMenuClickInfo {
  key: string
  keyPath: string[]
  item: unknown
  domEvent: MouseEvent
}

interface IRangePresetItem {
  label: string
  value: [Dayjs, Dayjs]
}

const loading = ref(false)
const dateRange = ref<[Dayjs, Dayjs] | undefined>(undefined)
const departmentId = ref<string | undefined>(undefined)

const summary = ref<IUsageSummary | null>(null)
const byModel = ref<IUsageByModel[]>([])
const topUsers = ref<IUsageTopUser[]>([])
const departments = ref<IDepartment[]>([])

const rangePresets: IRangePresetItem[] = [
  { label: '今天', value: [dayjs().startOf('day'), dayjs().endOf('day')] },
  { label: '最近 7 天', value: [dayjs().subtract(6, 'day').startOf('day'), dayjs().endOf('day')] },
  { label: '最近 30 天', value: [dayjs().subtract(29, 'day').startOf('day'), dayjs().endOf('day')] },
  { label: '本月', value: [dayjs().startOf('month'), dayjs().endOf('month')] },
]

const deptOptions = computed<ISelectOption[]>(() =>
  departments.value.map((d) => ({ label: d.name, value: d.id })),
)

const deptRows = computed<IDeptUsageRow[]>(() => {
  const map: Record<string, IUsageMetric> = summary.value?.by_department ?? {}
  return Object.entries(map).map(([departmentId, v]) => ({
    department_id: departmentId,
    tokens: v.total_tokens,
    cost: v.total_cost,
    requests: v.count,
  }))
})

const modelColumns: TableColumnType<IUsageByModel>[] = [
  { title: '模型', key: 'model', dataIndex: 'model', width: 200, ellipsis: true },
  { title: 'Token', key: 'tokens', width: 140 },
  { title: '成本 (USD)', key: 'cost', width: 130 },
  { title: '请求数', key: 'requests', dataIndex: 'requests', width: 100 },
]

const userColumns: TableColumnType<IUsageTopUser>[] = [
  { title: '用户 ID', key: 'user_id', dataIndex: 'user_id', width: 200, ellipsis: true },
  { title: 'Token', key: 'tokens', width: 140 },
  { title: '成本 (USD)', key: 'cost', width: 130 },
  { title: '请求数', key: 'requests', dataIndex: 'requests', width: 100 },
]

const deptColumns: TableColumnType<IDeptUsageRow>[] = [
  { title: '部门 ID', key: 'department_id', dataIndex: 'department_id', width: 220, ellipsis: true },
  { title: 'Token', key: 'tokens', width: 160 },
  { title: '成本 (USD)', key: 'cost', width: 150 },
  { title: '请求数', key: 'requests', dataIndex: 'requests', width: 120 },
]

function buildParams(): { start?: string; end?: string; department_id?: string } {
  const params: { start?: string; end?: string; department_id?: string } = {}
  if (dateRange.value && dateRange.value.length === 2) {
    params.start = dateRange.value[0].startOf('day').toISOString()
    params.end = dateRange.value[1].endOf('day').toISOString()
  }
  if (departmentId.value) {
    params.department_id = departmentId.value
  }
  return params
}

function formatNumber(n: number): string {
  if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(2)}M`
  if (n >= 1_000) return `${(n / 1_000).toFixed(2)}K`
  return String(n)
}

function formatCost(n: number): string {
  return `$${n.toFixed(4)}`
}

function extractMessage(err: unknown, fallback: string): string {
  if (err && typeof err === 'object') {
    const obj = err as { detail?: unknown; message?: unknown }
    if (typeof obj.detail === 'string' && obj.detail) return obj.detail
    if (typeof obj.message === 'string' && obj.message) return obj.message
  }
  return fallback
}

async function loadDepartments(): Promise<void> {
  try {
    departments.value = await adminApi.listDepartments()
  } catch (err) {
    message.error(extractMessage(err, '加载部门列表失败'))
  }
}

async function loadSummary(): Promise<void> {
  try {
    summary.value = await adminApi.getUsageSummary(buildParams())
  } catch (err) {
    message.error(extractMessage(err, '加载用量汇总失败'))
  }
}

async function loadByModel(): Promise<void> {
  try {
    byModel.value = await adminApi.getUsageByModel(buildParams())
  } catch (err) {
    message.error(extractMessage(err, '加载模型分布失败'))
  }
}

async function loadTopUsers(): Promise<void> {
  try {
    const params = buildParams()
    topUsers.value = await adminApi.getUsageTopUsers({
      department_id: params.department_id,
      limit: 20,
    })
  } catch (err) {
    message.error(extractMessage(err, '加载 Top 用户失败'))
  }
}

async function loadAll(): Promise<void> {
  loading.value = true
  await Promise.all([loadSummary(), loadByModel(), loadTopUsers()])
  loading.value = false
}

async function handleExport(info: IMenuClickInfo): Promise<void> {
  const format = info.key === 'json' ? 'json' : 'csv'
  try {
    const content = await adminApi.exportUsage({ ...buildParams(), format })
    const mime = format === 'json' ? 'application/json;charset=utf-8' : 'text/csv;charset=utf-8'
    const ext = format === 'json' ? 'json' : 'csv'
    const blob = new Blob([content], { type: mime })
    const url = URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    const stamp = dayjs().format('YYYYMMDD-HHmmss')
    link.download = `usage-${stamp}.${ext}`
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    URL.revokeObjectURL(url)
    message.success(`已导出 ${format.toUpperCase()} 报表`)
  } catch (err) {
    message.error(extractMessage(err, '导出报表失败'))
  }
}

onMounted(async () => {
  await Promise.all([loadDepartments(), loadAll()])
})
</script>

<style scoped>
.usage-view {
  padding: 24px;
  max-width: 1200px;
  margin: 0 auto;
}

.usage-view__header {
  margin-bottom: 16px;
}

.usage-view__filters {
  margin-bottom: var(--space-4);
}

.usage-view__stats {
  margin-bottom: var(--space-4);
}

.usage-view__stat-hint {
  margin-top: var(--space-2);
  font-size: var(--font-xs);
  color: var(--text-tertiary);
}

.usage-view__tables {
  margin-bottom: var(--space-4);
}

.usage-view__table-card {
  height: 100%;
}

.usage-view__dept-card {
  margin-top: 0;
}
</style>
