<script setup>
import { computed, inject, onMounted, onUnmounted, ref } from 'vue'
import {
  Calendar,
  ChatLineSquare,
  Clock,
  Cpu,
  Key,
  Loading,
  Message,
  Star,
  Tickets,
  Tools,
  TrendCharts,
  UserFilled,
} from '@element-plus/icons-vue'

import { fetchFeedbackStats } from '../api/feedbacks'
import { fetchEmailStats } from '../api/email'
import { fetchDockerStats, fetchRequestMetrics, fetchRunningTasks, fetchServerInfo, fetchSlowSqlMetrics, fetchTaskStats } from '../api/tasks'
import { fetchBrowserPoolStats } from '../api/browser_pool'
import { fetchSystemConfig } from '../api/system'
import MetricGrid from '../components/MetricGrid.vue'

const refreshStats = inject('refreshStats', null)
const adminStats = inject('adminStats', null)

const loading = ref(false)
const refreshing = ref(false)
const lastUpdatedAt = ref('')

const taskStats = ref(null)
const runningTasks = ref(null)
const emailStats = ref(null)
const feedbackStats = ref(null)
const serverInfo = ref(null)
const dockerStats = ref(null)
const browserPoolStats = ref(null)
const systemConfig = ref(null)
const requestMetrics = ref(null)
const slowSqlMetrics = ref(null)
const requestDetailsOpen = ref(false)
const slowSqlDetailsOpen = ref(false)
const queueTab = ref('running')

function recordUpdatedAt() {
  try {
    lastUpdatedAt.value = new Date().toLocaleString('zh-CN', { hour12: false, timeZone: 'Asia/Shanghai' })
  } catch {
    lastUpdatedAt.value = ''
  }
}

function normalizeCount(value) {
  const n = Number(value)
  return Number.isFinite(n) ? n : 0
}

function parsePercent(value) {
  const text = String(value ?? '').trim()
  if (!text) return 0
  const cleaned = text.endsWith('%') ? text.slice(0, -1) : text
  const n = Number(cleaned)
  if (!Number.isFinite(n)) return 0
  if (n < 0) return 0
  if (n > 1000) return 1000
  return n
}

function percentText(value) {
  return `${Math.round(parsePercent(value))}%`
}

function formatMs(value) {
  const n = Number(value)
  if (!Number.isFinite(n) || n < 0) return '-'
  if (n >= 100) return `${Math.round(n)}ms`
  return `${n.toFixed(1)}ms`
}

function formatUnixTime(value) {
  const ts = Number(value)
  if (!Number.isFinite(ts) || ts <= 0) return '-'
  try {
    return new Date(ts * 1000).toLocaleTimeString('zh-CN', { hour12: false, timeZone: 'Asia/Shanghai' })
  } catch {
    return '-'
  }
}

function formatUnixDateTime(value) {
  const ts = Number(value)
  if (!Number.isFinite(ts) || ts <= 0) return '-'
  try {
    return new Date(ts * 1000).toLocaleString('zh-CN', { hour12: false, timeZone: 'Asia/Shanghai' })
  } catch {
    return '-'
  }
}

function sourceLabel(source) {
  const raw = String(source ?? '').trim()
  if (!raw) return '手动'
  if (raw === 'manual') return '手动'
  if (raw === 'scheduled') return '系统定时'
  if (raw === 'batch') return '批量执行'
  if (raw === 'resumed') return '断点续跑'
  if (raw.startsWith('user_scheduled:')) return '用户定时'
  return raw
}

const overviewCards = computed(() => {
  const s = adminStats?.value || {}
  const liveMax = normalizeCount(runningTasks.value?.max_concurrent)
  return [
    { label: '总用户数', value: normalizeCount(s.total_users), icon: UserFilled, tone: 'blue' },
    { label: '今日注册', value: normalizeCount(s.new_users_today), icon: Calendar, tone: 'green' },
    { label: '近7天注册', value: normalizeCount(s.new_users_7d), icon: TrendCharts, tone: 'purple' },
    { label: '总账号数', value: normalizeCount(s.total_accounts), icon: Key, tone: 'cyan' },
    { label: 'VIP用户', value: normalizeCount(s.vip_users), icon: Star, tone: 'orange' },
    {
      label: '运行中任务',
      value: normalizeCount(runningTasks.value?.running_count),
      icon: Loading,
      tone: 'green',
      sub: liveMax ? `并发上限 ${liveMax}` : '',
    },
    { label: '排队任务', value: normalizeCount(runningTasks.value?.queuing_count), icon: Clock, tone: 'purple' },
  ]
})

const taskToday = computed(() => taskStats.value?.today || {})
const taskTotal = computed(() => taskStats.value?.total || {})
const runningTaskList = computed(() => runningTasks.value?.running || [])
const queuingTaskList = computed(() => runningTasks.value?.queuing || [])
const runningCount = computed(() => normalizeCount(runningTasks.value?.running_count))
const queuingCount = computed(() => normalizeCount(runningTasks.value?.queuing_count))

const browserPoolWorkers = computed(() => {
  const workers = browserPoolStats.value?.workers
  if (!Array.isArray(workers)) return []
  return [...workers].sort((a, b) => normalizeCount(a?.worker_id) - normalizeCount(b?.worker_id))
})

const browserPoolTotalWorkers = computed(() => normalizeCount(browserPoolStats.value?.total_workers))
const browserPoolActiveWorkers = computed(() => browserPoolWorkers.value.filter((w) => Boolean(w?.has_browser)).length)
const browserPoolIdleWorkers = computed(() => normalizeCount(browserPoolStats.value?.idle_workers))
const browserPoolQueueSize = computed(() => normalizeCount(browserPoolStats.value?.queue_size))
const browserPoolBusyWorkers = computed(() => normalizeCount(browserPoolStats.value?.active_workers))

function workerPoolStatusType(worker) {
  if (!worker?.thread_alive) return 'danger'
  if (worker?.has_browser) return 'success'
  return 'info'
}

function workerPoolStatusLabel(worker) {
  if (!worker?.thread_alive) return '异常'
  if (worker?.has_browser) return '活跃'
  return '空闲'
}

function workerRunTagType(worker) {
  if (!worker?.thread_alive) return 'danger'
  return worker?.idle ? 'info' : 'warning'
}

function workerRunLabel(worker) {
  if (!worker?.thread_alive) return '停止'
  return worker?.idle ? '空闲' : '忙碌'
}

const taskTodaySuccessRate = computed(() => {
  const success = normalizeCount(taskToday.value.success_tasks)
  const failed = normalizeCount(taskToday.value.failed_tasks)
  const total = success + failed
  return total > 0 ? Math.round((success / total) * 1000) / 10 : 0
})

const emailSuccessRate = computed(() => normalizeCount(emailStats.value?.success_rate))

const taskTodayCards = computed(() => [
  { label: '总任务', value: normalizeCount(taskToday.value.total_tasks), tone: 'blue' },
  { label: '成功', value: normalizeCount(taskToday.value.success_tasks), tone: 'green' },
  { label: '失败', value: normalizeCount(taskToday.value.failed_tasks), tone: 'red' },
  { label: '浏览内容', value: normalizeCount(taskToday.value.total_items), tone: 'purple' },
  { label: '查看附件', value: normalizeCount(taskToday.value.total_attachments), tone: 'cyan' },
])

const taskTotalCards = computed(() => [
  { label: '总任务', value: normalizeCount(taskTotal.value.total_tasks), tone: 'blue' },
  { label: '成功', value: normalizeCount(taskTotal.value.success_tasks), tone: 'green' },
  { label: '失败', value: normalizeCount(taskTotal.value.failed_tasks), tone: 'red' },
  { label: '浏览内容', value: normalizeCount(taskTotal.value.total_items), tone: 'purple' },
  { label: '查看附件', value: normalizeCount(taskTotal.value.total_attachments), tone: 'cyan' },
])

const emailCards = computed(() => [
  { label: '总发送', value: normalizeCount(emailStats.value?.total_sent), tone: 'blue' },
  { label: '成功', value: normalizeCount(emailStats.value?.total_success), tone: 'green' },
  { label: '失败', value: normalizeCount(emailStats.value?.total_failed), tone: 'red' },
  { label: '成功率', value: `${emailSuccessRate.value}%`, tone: 'purple' },
])

const emailTypeCards = computed(() => [
  { label: '注册验证', value: normalizeCount(emailStats.value?.register_sent), tone: 'cyan' },
  { label: '密码重置', value: normalizeCount(emailStats.value?.reset_sent), tone: 'orange' },
  { label: '邮箱绑定', value: normalizeCount(emailStats.value?.bind_sent), tone: 'purple' },
  { label: '任务完成', value: normalizeCount(emailStats.value?.task_complete_sent), tone: 'green' },
])

const feedbackCards = computed(() => [
  { label: '总反馈', value: normalizeCount(feedbackStats.value?.total), tone: 'blue' },
  { label: '待处理', value: normalizeCount(feedbackStats.value?.pending), tone: 'orange' },
  { label: '已回复', value: normalizeCount(feedbackStats.value?.replied), tone: 'green' },
])

const browserPoolCards = computed(() => [
  { label: '总 Worker', value: browserPoolTotalWorkers.value, tone: 'blue' },
  { label: '活跃 Worker', value: browserPoolActiveWorkers.value, tone: 'green' },
  { label: '空闲 Worker', value: browserPoolIdleWorkers.value, tone: 'cyan' },
  { label: '忙碌 Worker', value: browserPoolBusyWorkers.value, tone: 'orange' },
  { label: '队列', value: browserPoolQueueSize.value, tone: 'purple' },
])

const scheduleEnabled = computed(() => (systemConfig.value?.schedule_enabled ?? 0) === 1)
const scheduleTime = computed(() => systemConfig.value?.schedule_time || '-')
const scheduleBrowseType = computed(() => systemConfig.value?.schedule_browse_type || '-')
const scheduleWeekdays = computed(() => String(systemConfig.value?.schedule_weekdays || '').trim())
const scheduleWeekdaysDisplay = computed(() => {
  const raw = scheduleWeekdays.value
  if (!raw) return ''
  const map = {
    1: '周一',
    2: '周二',
    3: '周三',
    4: '周四',
    5: '周五',
    6: '周六',
    7: '周日',
  }
  const parts = raw
    .split(',')
    .map((x) => x.trim())
    .filter(Boolean)
  if (!parts.length) return raw
  return parts.map((p) => map[Number(p)] || p).join('、')
})

const proxyEnabled = computed(() => (systemConfig.value?.proxy_enabled ?? 0) === 1)
const proxyApiUrl = computed(() => systemConfig.value?.proxy_api_url || '')
const proxyExpireMinutes = computed(() => normalizeCount(systemConfig.value?.proxy_expire_minutes))

const maxConcurrentGlobal = computed(() => normalizeCount(systemConfig.value?.max_concurrent_global))
const maxConcurrentPerAccount = computed(() => normalizeCount(systemConfig.value?.max_concurrent_per_account))
const maxScreenshotConcurrent = computed(() => normalizeCount(systemConfig.value?.max_screenshot_concurrent))

const runningCountsLabel = computed(() => {
  const runningCount = normalizeCount(runningTasks.value?.running_count)
  const queuingCount = normalizeCount(runningTasks.value?.queuing_count)
  const maxGlobal = normalizeCount(runningTasks.value?.max_concurrent)
  return `运行中 ${runningCount} / 排队 ${queuingCount} / 并发上限 ${maxGlobal || maxConcurrentGlobal.value || '-'}`
})

const overviewModuleItems = computed(() =>
  overviewCards.value.map((item) => ({
    label: item.label,
    value: item.sub ? `${item.value}（${item.sub}）` : item.value,
  })),
)

const taskModuleItems = computed(() => [
  { label: '今日总任务', value: normalizeCount(taskToday.value.total_tasks) },
  { label: '今日成功', value: normalizeCount(taskToday.value.success_tasks) },
  { label: '今日失败', value: normalizeCount(taskToday.value.failed_tasks) },
  { label: '今日成功率', value: `${taskTodaySuccessRate.value}%` },
  { label: '累计任务', value: normalizeCount(taskTotal.value.total_tasks) },
  { label: '累计成功', value: normalizeCount(taskTotal.value.success_tasks) },
])

const queueModuleItems = computed(() => [
  { label: '运行中', value: runningCount.value },
  { label: '排队中', value: queuingCount.value },
  { label: '并发上限', value: normalizeCount(runningTasks.value?.max_concurrent) || maxConcurrentGlobal.value || '-' },
  { label: '排队首条来源', value: sourceLabel(queuingTaskList.value[0]?.source) },
  { label: '排队首条状态', value: queuingTaskList.value[0]?.detail_status || queuingTaskList.value[0]?.status || '-' },
  { label: '最长等待', value: queuingTaskList.value[0]?.elapsed_display || '-' },
])

const emailModuleItems = computed(() => [
  { label: '总发送', value: normalizeCount(emailStats.value?.total_sent) },
  { label: '成功', value: normalizeCount(emailStats.value?.total_success) },
  { label: '失败', value: normalizeCount(emailStats.value?.total_failed) },
  { label: '成功率', value: `${emailSuccessRate.value}%` },
  { label: '注册验证', value: normalizeCount(emailStats.value?.register_sent) },
  { label: '重置密码', value: normalizeCount(emailStats.value?.reset_sent) },
])

const feedbackModuleItems = computed(() => [
  { label: '总反馈', value: normalizeCount(feedbackStats.value?.total) },
  { label: '待处理', value: normalizeCount(feedbackStats.value?.pending) },
  { label: '已回复', value: normalizeCount(feedbackStats.value?.replied) },
])

const resourceModuleItems = computed(() => [
  { label: 'CPU', value: percentText(serverInfo.value?.cpu_percent) },
  { label: '内存', value: percentText(serverInfo.value?.memory_percent) },
  { label: '磁盘', value: percentText(serverInfo.value?.disk_percent) },
  { label: '容器状态', value: dockerStats.value?.status || '-' },
  { label: '容器名', value: dockerStats.value?.container_name || '-' },
  { label: '容器运行', value: dockerStats.value?.uptime || '-' },
])

const workerModuleItems = computed(() => [
  { label: '总 Worker', value: browserPoolTotalWorkers.value },
  { label: '活跃 Worker', value: browserPoolActiveWorkers.value },
  { label: '忙碌 Worker', value: browserPoolBusyWorkers.value },
  { label: '空闲 Worker', value: browserPoolIdleWorkers.value },
  { label: '任务队列', value: browserPoolQueueSize.value },
])

const requestTopPaths = computed(() => {
  const rows = requestMetrics.value?.top_paths
  if (!Array.isArray(rows)) return []
  return rows.slice(0, 3)
})

const requestModuleItems = computed(() => {
  const items = [
    { label: '总请求', value: normalizeCount(requestMetrics.value?.total_requests) },
    { label: 'API请求', value: normalizeCount(requestMetrics.value?.api_requests) },
    { label: '慢请求', value: normalizeCount(requestMetrics.value?.slow_requests) },
    { label: '错误请求', value: normalizeCount(requestMetrics.value?.error_requests) },
  ]

  requestTopPaths.value.forEach((row, index) => {
    const pathText = String(row?.path || '-')
    items.push({
      label: `慢接口${index + 1}`,
      value: `${pathText} · 峰值 ${formatMs(row?.max_ms)}`,
    })
  })

  return items
})

const requestModuleDesc = computed(() => {
  const avgMs = formatMs(requestMetrics.value?.avg_duration_ms)
  const maxMs = formatMs(requestMetrics.value?.max_duration_ms)
  const lastAt = formatUnixTime(requestMetrics.value?.last_request_ts)
  const slowThreshold = formatMs(requestMetrics.value?.slow_threshold_ms)
  return `均值 ${avgMs} · 峰值 ${maxMs} · 慢阈 ${slowThreshold} · 最近 ${lastAt}`
})

const slowSqlTopRows = computed(() => {
  const rows = Array.isArray(slowSqlMetrics.value?.top_sql) ? slowSqlMetrics.value.top_sql : []
  return rows.slice(0, 3)
})

const slowSqlWindowHours = computed(() => {
  const seconds = normalizeCount(slowSqlMetrics.value?.window_seconds)
  if (seconds <= 0) return 24
  return Math.max(1, Math.round(seconds / 3600))
})

const slowSqlModuleItems = computed(() => {
  const items = [
    { label: `慢SQL(${slowSqlWindowHours.value}h)`, value: normalizeCount(slowSqlMetrics.value?.total_slow_queries) },
    { label: '去重SQL', value: normalizeCount(slowSqlMetrics.value?.unique_sql) },
    { label: '平均耗时', value: formatMs(slowSqlMetrics.value?.avg_duration_ms) },
    { label: '峰值耗时', value: formatMs(slowSqlMetrics.value?.max_duration_ms) },
  ]

  slowSqlTopRows.value.forEach((row, index) => {
    items.push({
      label: `慢SQL${index + 1}`,
      value: `${formatMs(row?.max_ms)} · ${String(row?.sql || '-')}`,
    })
  })

  return items
})

const slowSqlModuleDesc = computed(() => {
  const threshold = formatMs(slowSqlMetrics.value?.slow_threshold_ms)
  const lastAt = formatUnixTime(slowSqlMetrics.value?.last_slow_ts)
  return `窗口 ${slowSqlWindowHours.value}h · 慢阈 ${threshold} · 最近 ${lastAt}`
})

const slowSqlDetailTopRows = computed(() => {
  const rows = Array.isArray(slowSqlMetrics.value?.top_sql) ? slowSqlMetrics.value.top_sql : []
  return rows.map((row, index) => ({
    rank: index + 1,
    sql: String(row?.sql || '-'),
    count: normalizeCount(row?.count),
    avg_ms: formatMs(row?.avg_ms),
    max_ms: formatMs(row?.max_ms),
    last_seen: formatUnixDateTime(row?.last_ts),
    sample_params: String(row?.sample_params || '-'),
  }))
})

const slowSqlRecentRows = computed(() => {
  const rows = Array.isArray(slowSqlMetrics.value?.recent_slow_sql) ? slowSqlMetrics.value.recent_slow_sql : []
  return [...rows]
    .sort((a, b) => Number(b?.time || 0) - Number(a?.time || 0))
    .map((row) => ({
      time_text: formatUnixDateTime(row?.time),
      sql: String(row?.sql || '-'),
      duration_ms: formatMs(row?.duration_ms),
      params: String(row?.params || '-'),
    }))
})

const requestDetailTopPaths = computed(() => {
  const rows = Array.isArray(requestMetrics.value?.top_paths) ? requestMetrics.value.top_paths : []
  return rows.map((row, index) => ({
    rank: index + 1,
    path: String(row?.path || '-'),
    count: normalizeCount(row?.count),
    avg_ms: formatMs(row?.avg_ms),
    max_ms: formatMs(row?.max_ms),
    status_5xx: normalizeCount(row?.status_5xx),
  }))
})

const requestRecentSlowRows = computed(() => {
  const rows = Array.isArray(requestMetrics.value?.recent_slow) ? requestMetrics.value.recent_slow : []
  return [...rows]
    .sort((a, b) => Number(b?.time || 0) - Number(a?.time || 0))
    .map((row) => ({
      time_text: formatUnixDateTime(row?.time),
      method: String(row?.method || '-').toUpperCase(),
      path: String(row?.path || '-'),
      status: normalizeCount(row?.status),
      duration_ms: formatMs(row?.duration_ms),
    }))
})

function requestStatusTagType(status) {
  const code = normalizeCount(status)
  if (code >= 500) return 'danger'
  if (code >= 400) return 'warning'
  if (code >= 300) return 'info'
  return 'success'
}

function openRequestDetails() {
  requestDetailsOpen.value = true
}

function openSlowSqlDetails() {
  slowSqlDetailsOpen.value = true
}

const reportSlowSqlThreshold = computed(() => {
  const runtimeThreshold = slowSqlMetrics.value?.slow_threshold_ms
  if (runtimeThreshold !== undefined && runtimeThreshold !== null) {
    return formatMs(runtimeThreshold)
  }
  const configThreshold = systemConfig.value?.db_slow_query_ms
  if (configThreshold !== undefined && configThreshold !== null) {
    return formatMs(configThreshold)
  }
  return '-'
})

const configModuleItems = computed(() => [
  { label: '定时任务', value: scheduleEnabled.value ? '启用' : '关闭' },
  { label: '执行时间', value: scheduleTime.value || '-' },
  { label: '浏览类型', value: scheduleBrowseType.value || '-' },
  { label: '代理', value: proxyEnabled.value ? '启用' : '关闭' },
  { label: '代理有效期', value: proxyExpireMinutes.value ? `${proxyExpireMinutes.value} 分钟` : '-' },
  { label: '全局并发', value: maxConcurrentGlobal.value || '-' },
  { label: '单账号并发', value: maxConcurrentPerAccount.value || '-' },
  { label: '截图并发', value: maxScreenshotConcurrent.value || '-' },
  { label: '慢SQL阈值', value: reportSlowSqlThreshold.value },
])

const mobileModules = computed(() => [
  {
    key: 'overview',
    title: '平台概览',
    desc: lastUpdatedAt.value ? `更新 ${lastUpdatedAt.value}` : '核心指标',
    tone: 'blue',
    items: overviewModuleItems.value,
  },
  {
    key: 'task',
    title: '任务概览',
    desc: normalizeCount(taskToday.value.total_tasks) > 0 ? `今日成功率 ${taskTodaySuccessRate.value}%` : '今日暂无任务',
    tone: 'purple',
    items: taskModuleItems.value,
  },
  {
    key: 'queue',
    title: '队列监控',
    desc: runningCountsLabel.value,
    tone: 'blue',
    items: queueModuleItems.value,
  },
  {
    key: 'email',
    title: '邮件报表',
    desc: `成功率 ${emailSuccessRate.value}%`,
    tone: 'cyan',
    items: emailModuleItems.value,
  },
  {
    key: 'feedback',
    title: '反馈概览',
    desc: `待处理 ${normalizeCount(feedbackStats.value?.pending)} 条`,
    tone: 'orange',
    items: feedbackModuleItems.value,
  },
  {
    key: 'resource',
    title: '系统资源',
    desc: serverInfo.value?.uptime ? `运行 ${serverInfo.value.uptime}` : '运行状态获取中',
    tone: 'green',
    items: resourceModuleItems.value,
  },
  {
    key: 'request',
    title: '接口性能',
    desc: requestModuleDesc.value,
    tone: 'purple',
    items: requestModuleItems.value,
  },
  {
    key: 'slow_sql',
    title: '慢SQL监控',
    desc: slowSqlModuleDesc.value,
    tone: 'red',
    items: slowSqlModuleItems.value,
  },
  {
    key: 'worker',
    title: '截图线程池',
    desc: `活跃 ${browserPoolActiveWorkers.value} · 忙碌 ${browserPoolBusyWorkers.value}`,
    tone: 'cyan',
    items: workerModuleItems.value,
  },
  {
    key: 'config',
    title: '配置概览',
    desc: '并发 / 代理 / 定时任务',
    tone: 'red',
    items: configModuleItems.value,
  },
])

const REPORT_SYNC_STATS_EVERY = 3
let reportRefreshTick = 1

async function refreshAll(options = {}) {
  const showLoading = options.showLoading ?? true
  if (refreshing.value) return

  const forceStatsSync = Boolean(options.forceStatsSync)
  const shouldSyncStats = forceStatsSync || reportRefreshTick % REPORT_SYNC_STATS_EVERY === 0
  reportRefreshTick += 1

  refreshing.value = true
  if (showLoading) {
    loading.value = true
  }
  try {
    const [
      taskResult,
      runningResult,
      emailResult,
      feedbackResult,
      serverResult,
      dockerResult,
      browserPoolResult,
      requestMetricsResult,
      slowSqlResult,
      configResult,
    ] = await Promise.allSettled([
      fetchTaskStats(),
      fetchRunningTasks(),
      fetchEmailStats(),
      fetchFeedbackStats(),
      fetchServerInfo(),
      fetchDockerStats(),
      fetchBrowserPoolStats(),
      fetchRequestMetrics(),
      fetchSlowSqlMetrics(),
      fetchSystemConfig(),
    ])

    if (taskResult.status === 'fulfilled') taskStats.value = taskResult.value
    if (runningResult.status === 'fulfilled') runningTasks.value = runningResult.value
    if (emailResult.status === 'fulfilled') emailStats.value = emailResult.value
    if (feedbackResult.status === 'fulfilled') feedbackStats.value = feedbackResult.value
    if (serverResult.status === 'fulfilled') serverInfo.value = serverResult.value
    if (dockerResult.status === 'fulfilled') dockerStats.value = dockerResult.value
    if (browserPoolResult.status === 'fulfilled') browserPoolStats.value = browserPoolResult.value
    if (requestMetricsResult.status === 'fulfilled') requestMetrics.value = requestMetricsResult.value
    if (slowSqlResult.status === 'fulfilled') slowSqlMetrics.value = slowSqlResult.value
    if (configResult.status === 'fulfilled') systemConfig.value = configResult.value

    if (shouldSyncStats) {
      await refreshStats?.({ force: forceStatsSync })
    }
    recordUpdatedAt()
  } finally {
    refreshing.value = false
    if (showLoading) {
      loading.value = false
    }
  }
}

const REPORT_POLL_ACTIVE_MS = 5000
const REPORT_POLL_HIDDEN_MS = 20000

let refreshTimer = null

function isPageHidden() {
  if (typeof document === 'undefined') return false
  return document.visibilityState === 'hidden'
}

function currentRefreshDelay() {
  return isPageHidden() ? REPORT_POLL_HIDDEN_MS : REPORT_POLL_ACTIVE_MS
}

function stopRefreshLoop() {
  if (!refreshTimer) return
  clearTimeout(refreshTimer)
  refreshTimer = null
}

function scheduleRefreshLoop() {
  stopRefreshLoop()
  refreshTimer = window.setTimeout(async () => {
    refreshTimer = null
    await refreshAll({ showLoading: false }).catch(() => {})
    scheduleRefreshLoop()
  }, currentRefreshDelay())
}

function onVisibilityChange() {
  scheduleRefreshLoop()
}

onMounted(() => {
  refreshAll({ showLoading: false })
    .catch(() => {})
    .finally(() => {
      scheduleRefreshLoop()
    })
  window.addEventListener('visibilitychange', onVisibilityChange)
})

onUnmounted(() => {
  stopRefreshLoop()
  window.removeEventListener('visibilitychange', onVisibilityChange)
})
</script>

<template>
  <div class="page-stack">
    <section class="report-hero">
      <div class="hero-head">
        <div class="hero-main">
          <h2>报表中心</h2>
          <div class="hero-meta app-muted">
            <span v-if="lastUpdatedAt">更新时间：{{ lastUpdatedAt }}</span>
            <span class="hero-dot">·</span>
            <span>慢SQL阈值 {{ reportSlowSqlThreshold }}</span>
            <span v-if="serverInfo?.uptime" class="hero-dot">·</span>
            <span v-if="serverInfo?.uptime">运行 {{ serverInfo.uptime }}</span>
          </div>
        </div>

      </div>

      <MetricGrid class="hero-overview-grid" :items="overviewCards" :loading="loading" :min-width="165" />
    </section>

    <section class="mobile-report">
      <el-card
        v-for="module in mobileModules"
        :key="module.key"
        shadow="never"
        class="mobile-module-card"
        :class="`mobile-tone-${module.tone}`"
        :body-style="{ padding: '12px' }"
      >
        <div class="mobile-module-head">
          <div class="mobile-module-title">{{ module.title }}</div>
          <div class="mobile-module-desc app-muted">{{ module.desc }}</div>
        </div>
        <div class="mobile-metrics">
          <div v-for="item in module.items" :key="`${module.key}-${item.label}`" class="mobile-metric-item">
            <div class="mobile-metric-label app-muted">{{ item.label }}</div>
            <div class="mobile-metric-value">{{ item.value }}</div>
          </div>
        </div>
        <div v-if="module.key === 'request' || module.key === 'slow_sql'" class="module-extra-actions">
          <el-button
            size="small"
            type="primary"
            plain
            @click="module.key === 'request' ? openRequestDetails() : openSlowSqlDetails()"
          >
            {{ module.key === 'request' ? '查看慢接口详情' : '查看慢SQL详情' }}
          </el-button>
        </div>
      </el-card>
    </section>

    <el-dialog v-model="requestDetailsOpen" title="慢接口详情" width="min(1080px, 96vw)">
      <div class="request-dialog-summary app-muted">
        <span>总请求：{{ normalizeCount(requestMetrics?.total_requests) }}</span>
        <span>API请求：{{ normalizeCount(requestMetrics?.api_requests) }}</span>
        <span>慢请求：{{ normalizeCount(requestMetrics?.slow_requests) }}</span>
        <span>错误请求：{{ normalizeCount(requestMetrics?.error_requests) }}</span>
      </div>

      <div class="request-dialog-block">
        <div class="request-dialog-title">慢接口排行榜</div>
        <div class="table-wrap">
          <el-table :data="requestDetailTopPaths" size="small" max-height="280">
            <el-table-column prop="rank" label="#" width="60" />
            <el-table-column prop="path" label="接口路径" min-width="340" show-overflow-tooltip />
            <el-table-column prop="count" label="请求数" width="100" />
            <el-table-column prop="avg_ms" label="平均耗时" width="120" />
            <el-table-column prop="max_ms" label="峰值耗时" width="120" />
            <el-table-column prop="status_5xx" label="5xx" width="90" />
          </el-table>
        </div>
      </div>

      <div class="request-dialog-block">
        <div class="request-dialog-title">最近慢请求</div>
        <div class="table-wrap">
          <el-table :data="requestRecentSlowRows" size="small" max-height="320">
            <el-table-column prop="time_text" label="时间" width="180" />
            <el-table-column prop="method" label="方法" width="90" />
            <el-table-column prop="path" label="接口路径" min-width="320" show-overflow-tooltip />
            <el-table-column label="状态" width="100">
              <template #default="scope">
                <el-tag size="small" :type="requestStatusTagType(scope.row.status)">{{ scope.row.status || '-' }}</el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="duration_ms" label="耗时" width="110" />
          </el-table>
        </div>
      </div>
    </el-dialog>

    <el-dialog v-model="slowSqlDetailsOpen" title="慢SQL详情（近24小时）" width="min(1080px, 96vw)">
      <div class="request-dialog-summary app-muted">
        <span>慢SQL总数：{{ normalizeCount(slowSqlMetrics?.total_slow_queries) }}</span>
        <span>去重SQL：{{ normalizeCount(slowSqlMetrics?.unique_sql) }}</span>
        <span>平均耗时：{{ formatMs(slowSqlMetrics?.avg_duration_ms) }}</span>
        <span>峰值耗时：{{ formatMs(slowSqlMetrics?.max_duration_ms) }}</span>
        <span>慢阈值：{{ formatMs(slowSqlMetrics?.slow_threshold_ms) }}</span>
      </div>

      <div class="request-dialog-block">
        <div class="request-dialog-title">TOP 慢SQL（按出现次数）</div>
        <div class="table-wrap">
          <el-table :data="slowSqlDetailTopRows" size="small" max-height="320">
            <el-table-column prop="rank" label="#" width="60" />
            <el-table-column prop="sql" label="SQL" min-width="400" show-overflow-tooltip />
            <el-table-column prop="count" label="次数" width="90" />
            <el-table-column prop="avg_ms" label="平均耗时" width="120" />
            <el-table-column prop="max_ms" label="峰值耗时" width="120" />
            <el-table-column prop="last_seen" label="最近出现" width="180" />
            <el-table-column prop="sample_params" label="参数样本" min-width="140" show-overflow-tooltip />
          </el-table>
        </div>
      </div>

      <div class="request-dialog-block">
        <div class="request-dialog-title">最近慢SQL</div>
        <div class="table-wrap">
          <el-table :data="slowSqlRecentRows" size="small" max-height="320">
            <el-table-column prop="time_text" label="时间" width="180" />
            <el-table-column prop="sql" label="SQL" min-width="420" show-overflow-tooltip />
            <el-table-column prop="duration_ms" label="耗时" width="110" />
            <el-table-column prop="params" label="参数" min-width="130" show-overflow-tooltip />
          </el-table>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<style scoped>
.page-stack {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.report-hero {
  position: relative;
  overflow: hidden;
  border-radius: 18px;
  border: 1px solid rgba(17, 24, 39, 0.1);
  background: radial-gradient(circle at 10% 10%, rgba(59, 130, 246, 0.18), transparent 48%),
    radial-gradient(circle at 80% 0%, rgba(236, 72, 153, 0.16), transparent 45%),
    radial-gradient(circle at 90% 90%, rgba(16, 185, 129, 0.14), transparent 42%),
    rgba(255, 255, 255, 0.72);
  box-shadow: 0 14px 40px rgba(15, 23, 42, 0.08);
  backdrop-filter: saturate(180%) blur(12px);
  padding: 16px;
}

.hero-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.hero-main h2 {
  margin: 0;
  font-size: 19px;
  font-weight: 900;
  letter-spacing: 0.2px;
}

.hero-meta {
  margin-top: 6px;
  font-size: 12px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.hero-dot {
  opacity: 0.65;
}

.hero-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}

.mobile-report {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.mobile-module-card {
  position: relative;
  overflow: hidden;
  border-radius: 14px;
  border: 1px solid rgba(17, 24, 39, 0.12);
  background: rgba(255, 255, 255, 0.9);
  box-shadow: var(--app-shadow-soft);
}

.mobile-module-card::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  height: 3px;
  background: var(--mobile-accent, #3b82f6);
}

.mobile-tone-blue {
  --mobile-accent: linear-gradient(90deg, #3b82f6, #06b6d4);
}

.mobile-tone-cyan {
  --mobile-accent: linear-gradient(90deg, #06b6d4, #3b82f6);
}

.mobile-tone-purple {
  --mobile-accent: linear-gradient(90deg, #8b5cf6, #ec4899);
}

.mobile-tone-orange {
  --mobile-accent: linear-gradient(90deg, #f59e0b, #f97316);
}

.mobile-tone-green {
  --mobile-accent: linear-gradient(90deg, #10b981, #22c55e);
}

.mobile-tone-red {
  --mobile-accent: linear-gradient(90deg, #ef4444, #f43f5e);
}

.mobile-module-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.mobile-module-title {
  font-size: 13px;
  font-weight: 900;
  color: #0f172a;
}

.mobile-module-desc {
  min-width: 0;
  max-width: 68%;
  font-size: 11px;
  line-height: 1.4;
  text-align: right;
}

.mobile-metrics {
  margin-top: 10px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.mobile-metric-item {
  padding: 8px 10px;
  border-radius: 10px;
  border: 1px solid rgba(17, 24, 39, 0.08);
  background: rgba(248, 250, 252, 0.9);
}

.mobile-metric-label {
  font-size: 11px;
  line-height: 1.35;
}

.mobile-metric-value {
  margin-top: 4px;
  font-size: 14px;
  font-weight: 800;
  color: #0f172a;
  line-height: 1.3;
  word-break: break-word;
}

.module-extra-actions {
  margin-top: 10px;
  display: flex;
  justify-content: flex-end;
}

.request-dialog-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 16px;
  font-size: 12px;
  margin-bottom: 12px;
}

.request-dialog-block + .request-dialog-block {
  margin-top: 14px;
}

.request-dialog-title {
  font-size: 13px;
  font-weight: 800;
  margin-bottom: 8px;
}

.hero-overview-grid {
  display: none;
}

.panel {
  border-radius: 18px;
  border: 1px solid rgba(17, 24, 39, 0.1);
  background: rgba(255, 255, 255, 0.72);
  box-shadow: var(--app-shadow);
  backdrop-filter: saturate(180%) blur(10px);
}

.panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.head-left {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.head-text {
  min-width: 0;
}

.head-icon {
  width: 40px;
  height: 40px;
  border-radius: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(17, 24, 39, 0.08);
  flex: 0 0 auto;
}

.tone-blue {
  background: rgba(59, 130, 246, 0.12);
  color: #1d4ed8;
}

.tone-cyan {
  background: rgba(34, 211, 238, 0.12);
  color: #0369a1;
}

.tone-purple {
  background: rgba(139, 92, 246, 0.12);
  color: #6d28d9;
}

.tone-orange {
  background: rgba(245, 158, 11, 0.12);
  color: #b45309;
}

.tone-green {
  background: rgba(16, 185, 129, 0.12);
  color: #047857;
}

.tone-red {
  background: rgba(239, 68, 68, 0.12);
  color: #b91c1c;
}

.panel-title {
  font-size: 14px;
  font-weight: 900;
}

.panel-sub {
  margin-top: 4px;
  font-size: 12px;
  color: var(--app-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.metrics-block {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.block-title {
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.2px;
}

.divider {
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(17, 24, 39, 0.12), transparent);
  margin: 14px 0;
}

.queue-tabs :deep(.el-tabs__header) {
  margin: 0 0 10px;
}

.tab-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.table-wrap {
  overflow-x: auto;
  border-radius: 10px;
  border: 1px solid var(--app-border);
  background: #fff;
}

.help {
  margin-top: 10px;
  font-size: 12px;
}

.resource-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.resource-item {
  border: 1px solid rgba(17, 24, 39, 0.08);
  border-radius: 16px;
  padding: 12px;
  background: rgba(255, 255, 255, 0.7);
}

.resource-k {
  font-size: 12px;
  margin-bottom: 8px;
}

.resource-sub {
  margin-top: 8px;
  font-size: 12px;
}

.config-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.config-item {
  border: 1px solid rgba(17, 24, 39, 0.08);
  border-radius: 16px;
  padding: 12px;
  background: rgba(255, 255, 255, 0.7);
}

.config-k {
  font-size: 12px;
}

.config-v {
  margin-top: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.config-inline {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.config-split {
  opacity: 0.65;
}

.config-sub {
  margin-top: 8px;
  font-size: 12px;
}

.err {
  color: #b91c1c;
}

:deep(.el-table) {
  --el-table-border-color: rgba(17, 24, 39, 0.08);
  --el-table-header-bg-color: rgba(246, 247, 251, 0.8);
}

:deep(.el-table th.el-table__cell) {
  background: rgba(246, 247, 251, 0.8);
}

@media (max-width: 1200px) {
  .mobile-report {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 768px) {
  .mobile-report {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .report-hero {
    border-radius: 14px;
    padding: 12px;
  }

  .hero-main h2 {
    font-size: 17px;
  }

  .hero-meta {
    margin-top: 4px;
    gap: 6px;
    font-size: 11px;
  }

  .resource-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 420px) {
  .mobile-metrics {
    grid-template-columns: 1fr;
  }

  .mobile-module-desc {
    max-width: 62%;
  }
}
</style>
