<script setup>
import * as echarts from 'echarts'
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'

import MetricTile from '../components/MetricTile.vue'
import PageHero from '../components/PageHero.vue'
import { useAsyncAction } from '../composables/useAsyncAction'
import { fetchDashboard } from '../api'
import { usePolling } from '../composables/usePolling'
import { formatCompactNumber, formatDate, formatDateTime, formatPercent } from '../utils/formatters'

const dashboard = ref({
  today: { total: 0, allowed: 0, intercepted: 0 },
  bindings: { active: 0, banned: 0 },
  trend: [],
  recent_intercepts: [],
})
const chartElement = ref(null)
const { loading, run } = useAsyncAction()
let chart

const interceptRate = computed(() => {
  const total = dashboard.value.today.total || 0
  if (!total) {
    return 0
  }
  return dashboard.value.today.intercepted / total
})

const bindingCoverage = computed(() => {
  const active = dashboard.value.bindings.active || 0
  const banned = dashboard.value.bindings.banned || 0
  const total = active + banned
  if (!total) {
    return 0
  }
  return active / total
})

async function renderChart() {
  await nextTick()
  if (!chartElement.value) {
    return
  }

  chart ||= echarts.init(chartElement.value)
  chart.setOption({
    animationDuration: 400,
    color: ['#4d8ff7', '#f29a44'],
    grid: {
      left: 24,
      right: 24,
      top: 40,
      bottom: 28,
      containLabel: true,
    },
    legend: {
      top: 0,
      textStyle: {
        color: '#5f7893',
        fontWeight: 600,
      },
    },
    tooltip: {
      trigger: 'axis',
      backgroundColor: 'rgba(34, 67, 108, 0.92)',
      borderWidth: 0,
      textStyle: {
        color: '#f7fffe',
      },
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: dashboard.value.trend.map((item) => item.date.slice(5)),
      axisLine: { lineStyle: { color: 'rgba(39, 74, 110, 0.16)' } },
      axisLabel: { color: '#5f7893', fontWeight: 600 },
    },
    yAxis: {
      type: 'value',
      splitLine: { lineStyle: { color: 'rgba(39, 74, 110, 0.08)' } },
      axisLabel: { color: '#5f7893' },
    },
    series: [
      {
        name: '放行',
        type: 'line',
        smooth: true,
        showSymbol: false,
        areaStyle: { color: 'rgba(77, 143, 247, 0.14)' },
        lineStyle: { width: 3 },
        data: dashboard.value.trend.map((item) => item.allowed),
      },
      {
        name: '拦截',
        type: 'line',
        smooth: true,
        showSymbol: false,
        areaStyle: { color: 'rgba(242, 154, 68, 0.12)' },
        lineStyle: { width: 3 },
        data: dashboard.value.trend.map((item) => item.intercepted),
      },
    ],
  })
}

async function loadDashboard() {
  await run(async () => {
    dashboard.value = await fetchDashboard()
    await renderChart()
  }, '加载看板失败。')
}

async function refreshDashboard() {
  try {
    await loadDashboard()
  } catch {}
}

function resizeChart() {
  chart?.resize()
}

const { start: startPolling, stop: stopPolling } = usePolling(refreshDashboard, 30000)

onMounted(async () => {
  await refreshDashboard()
  startPolling()
  window.addEventListener('resize', resizeChart)
})

onBeforeUnmount(() => {
  stopPolling()
  window.removeEventListener('resize', resizeChart)
  chart?.dispose()
})
</script>

<template>
  <div class="page-grid">
    <PageHero
      eyebrow="运行概览"
      title="在一个页面里查看放行、拦截与绑定状态"
      description="看板汇总今日代理结果、绑定规模和最近拦截记录，便于快速判断系统是否稳定运行。"
    >
      <template #aside>
        <div class="hero-stat-pair">
          <div class="hero-stat">
            <span class="eyebrow">拦截率</span>
            <strong>{{ formatPercent(interceptRate) }}</strong>
          </div>
          <div class="hero-stat">
            <span class="eyebrow">活跃占比</span>
            <strong>{{ formatPercent(bindingCoverage) }}</strong>
          </div>
        </div>
      </template>

      <template #actions>
        <el-button :loading="loading" type="primary" plain @click="refreshDashboard">刷新看板</el-button>
      </template>
    </PageHero>

    <section class="metric-grid">
      <MetricTile
        eyebrow="今日总量"
        :value="formatCompactNumber(dashboard.today.total)"
        note="今天经过网关处理的请求总数。"
        accent="slate"
      />
      <MetricTile
        eyebrow="放行请求"
        :value="formatCompactNumber(dashboard.today.allowed)"
        note="通过绑定校验并成功转发的请求。"
        accent="slate"
      />
      <MetricTile
        eyebrow="拦截请求"
        :value="formatCompactNumber(dashboard.today.intercepted)"
        note="因 IP 不匹配或 Token 被封禁而拦截。"
        accent="amber"
      />
      <MetricTile
        eyebrow="当前绑定"
        :value="formatCompactNumber(dashboard.bindings.active)"
        :note="`活跃绑定 ${formatCompactNumber(dashboard.bindings.active)} 条，封禁 ${formatCompactNumber(dashboard.bindings.banned)} 条。`"
        accent="slate"
      />
    </section>

    <section class="content-grid">
      <article class="chart-card panel">
        <div class="toolbar">
          <div>
            <p class="eyebrow">7 日趋势</p>
            <h3 class="section-title">近 7 天放行与拦截趋势</h3>
          </div>
          <div class="inline-meta">
            <el-tag round effect="plain" type="primary">30 秒自动刷新</el-tag>
            <span class="muted">结合 Redis 指标与 PostgreSQL 日志统计。</span>
          </div>
        </div>
        <div ref="chartElement" class="chart-surface" />
        <div class="trend-summary">
          <p class="eyebrow">趋势明细</p>
          <div class="trend-table-wrap">
            <table class="trend-table">
              <thead>
                <tr>
                  <th scope="col">日期</th>
                  <th scope="col">放行</th>
                  <th scope="col">拦截</th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="item in dashboard.trend" :key="item.date">
                  <td>{{ formatDate(item.date) }}</td>
                  <td>{{ formatCompactNumber(item.allowed) }}</td>
                  <td>{{ formatCompactNumber(item.intercepted) }}</td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>
      </article>

      <article class="table-card panel">
        <div class="table-toolbar-block">
          <p class="eyebrow">最新事件</p>
          <h3 class="section-title">最近拦截记录</h3>
          <p class="muted">用于快速确认异常来源、告警状态和是否需要进一步处置。</p>
        </div>

        <div v-if="!dashboard.recent_intercepts.length" class="empty-state">当前还没有拦截记录。</div>

        <div v-else class="table-stack table-stack--spaced">
          <article
            v-for="item in dashboard.recent_intercepts"
            :key="item.id"
            class="insight-card insight-card--compact"
          >
            <div class="toolbar">
              <strong>{{ item.token_display }}</strong>
              <el-tag :type="item.alerted ? 'danger' : 'warning'" round>
                {{ item.alerted ? '已告警' : '待观察' }}
              </el-tag>
            </div>
            <p class="insight-note">绑定地址：{{ item.bound_ip }}</p>
            <p class="insight-note">尝试地址：{{ item.attempt_ip }}</p>
            <p class="insight-note">{{ formatDateTime(item.intercepted_at) }}</p>
          </article>
        </div>
      </article>
    </section>
  </div>
</template>
