<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { logApi, type Log, type LogQueryParams, type LogStats } from '@/api/log'
import { Terminal, RefreshCw, Bot, MessageSquare, Settings, AlertCircle, ChevronDown, ChevronRight } from 'lucide-vue-next'

type TimePreset = '1h' | '6h' | '24h' | '7d' | 'custom'

interface LogFilters {
  preset: TimePreset
  start_at: string
  end_at: string
  request_id: string
  route: string
  operation: string
  status_code: string
  log_type: string
  level: string
  page: number
  page_size: number
}

const logs = ref<Log[]>([])
const stats = ref<LogStats | null>(null)
const loading = ref(false)
const errorMessage = ref('')
const expandedLogId = ref<string | null>(null)
const autoRefresh = ref(false)
let refreshInterval: ReturnType<typeof window.setInterval> | null = null

const pageSizeOptions = [20, 50, 100]
const timePresets: Array<{ value: TimePreset; label: string }> = [
  { value: '1h', label: '1h' },
  { value: '6h', label: '6h' },
  { value: '24h', label: '24h' },
  { value: '7d', label: '7d' },
  { value: 'custom', label: '自定义' },
]

const logTypes = [
  { value: '', label: '全部', icon: null },
  { value: 'agent', label: '智能体', icon: Bot },
  { value: 'system', label: '系统', icon: Settings },
  { value: 'chat', label: '问答', icon: MessageSquare },
]

const logLevels = [
  { value: '', label: '全部' },
  { value: 'debug', label: '调试' },
  { value: 'info', label: '信息' },
  { value: 'warning', label: '警告' },
  { value: 'error', label: '错误' },
]

const statusCodeOptions = [
  { value: '', label: '全部状态' },
  { value: '200', label: '200' },
  { value: '400', label: '400' },
  { value: '401', label: '401' },
  { value: '404', label: '404' },
  { value: '422', label: '422' },
  { value: '500', label: '500' },
]

const levelColors: Record<string, string> = {
  debug: 'var(--text-dim)',
  info: 'var(--accent-cyan)',
  warning: 'var(--accent-amber)',
  error: 'var(--accent-red)',
}

const typeLabels: Record<string, string> = {
  agent: '智能体',
  system: '系统',
  chat: '问答',
}

function toDatetimeLocalValue(date: Date): string {
  const offsetMs = date.getTimezoneOffset() * 60 * 1000
  return new Date(date.getTime() - offsetMs).toISOString().slice(0, 16)
}

function getPresetRange(preset: Exclude<TimePreset, 'custom'>) {
  const end = new Date()
  const start = new Date(end)
  const hours = preset === '1h' ? 1 : preset === '6h' ? 6 : preset === '24h' ? 24 : 24 * 7
  start.setHours(start.getHours() - hours)
  return {
    start_at: toDatetimeLocalValue(start),
    end_at: toDatetimeLocalValue(end),
  }
}

function createDefaultFilters(): LogFilters {
  return {
    preset: '24h',
    ...getPresetRange('24h'),
    request_id: '',
    route: '',
    operation: '',
    status_code: '',
    log_type: '',
    level: '',
    page: 1,
    page_size: 50,
  }
}

const filters = ref<LogFilters>(createDefaultFilters())
const totalPages = computed(() => Math.max(1, Math.ceil(total.value / filters.value.page_size)))
const visiblePageNumbers = computed(() => {
  const totalPageCount = totalPages.value
  const currentPage = filters.value.page
  if (totalPageCount <= 5) {
    return Array.from({ length: totalPageCount }, (_, index) => index + 1)
  }

  let startPage = Math.max(1, currentPage - 2)
  let endPage = Math.min(totalPageCount, startPage + 4)

  if (endPage - startPage < 4) {
    startPage = Math.max(1, endPage - 4)
  }

  return Array.from({ length: endPage - startPage + 1 }, (_, index) => startPage + index)
})
const total = ref(0)

function formatTime(dateStr: string | null): string {
  if (!dateStr) return '-'
  const d = new Date(dateStr)
  if (Number.isNaN(d.getTime())) return dateStr
  return d.toLocaleString('zh-CN', {
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    month: '2-digit',
    day: '2-digit',
  })
}

function formatDuration(ms: number | null): string {
  if (ms == null) return ''
  if (ms < 1000) return `${ms}ms`
  return `${(ms / 1000).toFixed(1)}s`
}

function formatDetails(details: Record<string, unknown> | null): string {
  if (!details) return ''
  return JSON.stringify(details, null, 2)
}

function toggleDetails(logId: string) {
  expandedLogId.value = expandedLogId.value === logId ? null : logId
}

function normalizeFilters(): LogQueryParams {
  return {
    log_type: filters.value.log_type || undefined,
    level: filters.value.level || undefined,
    request_id: filters.value.request_id.trim() || undefined,
    route: filters.value.route.trim() || undefined,
    operation: filters.value.operation.trim() || undefined,
    status_code: filters.value.status_code ? Number(filters.value.status_code) : undefined,
    start_at: filters.value.start_at ? new Date(filters.value.start_at).toISOString() : undefined,
    end_at: filters.value.end_at ? new Date(filters.value.end_at).toISOString() : undefined,
    page: filters.value.page,
    page_size: filters.value.page_size,
  }
}

function validateDateRange() {
  if (filters.value.start_at && filters.value.end_at && filters.value.start_at > filters.value.end_at) {
    errorMessage.value = '开始时间不能晚于结束时间'
    return false
  }
  return true
}

async function fetchLogs() {
  loading.value = true
  errorMessage.value = ''
  try {
    const requestedPage = filters.value.page
    const res = await logApi.list(normalizeFilters())
    logs.value = res.data.logs
    total.value = res.data.total
    const maxPage = Math.max(1, Math.ceil(res.data.total / filters.value.page_size))
    if (requestedPage > maxPage) {
      filters.value.page = maxPage
      if (maxPage !== requestedPage) {
        await fetchLogs()
      }
      return
    }
  } catch (e: unknown) {
    errorMessage.value = (e as { response?: { data?: { detail?: string } } })?.response?.data?.detail || '加载日志失败'
  } finally {
    loading.value = false
  }
}

async function fetchStats() {
  try {
    const res = await logApi.getStats(normalizeFilters())
    stats.value = res.data
  } catch {
    if (!errorMessage.value) {
      errorMessage.value = '加载日志统计失败'
    }
  }
}

async function loadData() {
  if (!validateDateRange()) return
  await Promise.all([fetchLogs(), fetchStats()])
}

function applyFilters() {
  filters.value.page = 1
  loadData()
}

function resetFilters() {
  filters.value = createDefaultFilters()
  loadData()
}

function applyPreset(preset: TimePreset) {
  filters.value.preset = preset
  if (preset !== 'custom') {
    const range = getPresetRange(preset)
    filters.value.start_at = range.start_at
    filters.value.end_at = range.end_at
  }
}

function markCustomRange() {
  filters.value.preset = 'custom'
}

function toggleAutoRefresh() {
  autoRefresh.value = !autoRefresh.value
  if (autoRefresh.value) {
    refreshInterval = window.setInterval(() => {
      loadData()
    }, 5000)
  } else if (refreshInterval) {
    clearInterval(refreshInterval)
    refreshInterval = null
  }
}

function goToPage(page: number) {
  if (page < 1 || page > totalPages.value || page === filters.value.page) {
    return
  }
  filters.value.page = page
  fetchLogs()
}

function prevPage() {
  goToPage(filters.value.page - 1)
}

function nextPage() {
  goToPage(filters.value.page + 1)
}

function changePageSize(size: number) {
  filters.value.page_size = size
  filters.value.page = 1
  loadData()
}

onMounted(loadData)

onUnmounted(() => {
  if (refreshInterval) {
    clearInterval(refreshInterval)
  }
})
</script>

<template>
  <div class="log-view">
    <div class="view-header">
      <div class="header-title">
        <Terminal :size="16" />
        <span>运行日志</span>
      </div>
      <div class="header-actions">
        <button class="btn-icon" :class="{ active: autoRefresh }" @click="toggleAutoRefresh" title="自动刷新">
          <RefreshCw :size="14" :class="{ spinning: autoRefresh }" />
        </button>
        <button class="btn-icon" @click="loadData" title="刷新">
          <RefreshCw :size="14" />
        </button>
      </div>
    </div>

    <div v-if="stats" class="stats-overview">
      <div class="stat-card">
        <div class="stat-label">总计</div>
        <div class="stat-value">{{ stats.total }}</div>
      </div>
      <div class="stat-card">
        <div class="stat-label">智能体</div>
        <div class="stat-value cyan">{{ stats.by_type.agent }}</div>
      </div>
      <div class="stat-card">
        <div class="stat-label">系统</div>
        <div class="stat-value purple">{{ stats.by_type.system }}</div>
      </div>
      <div class="stat-card">
        <div class="stat-label">问答</div>
        <div class="stat-value amber">{{ stats.by_type.chat }}</div>
      </div>
      <div class="stat-card">
        <div class="stat-label">错误</div>
        <div class="stat-value red">{{ stats.by_level.error }}</div>
      </div>
    </div>

    <div class="filters">
      <div class="toolbar-row presets-row">
        <button
          v-for="preset in timePresets"
          :key="preset.value"
          class="filter-btn"
          :class="{ active: filters.preset === preset.value }"
          @click="applyPreset(preset.value)"
        >
          {{ preset.label }}
        </button>
      </div>

      <div class="toolbar-row fields-row">
        <input v-model="filters.start_at" class="filter-input" type="datetime-local" @input="markCustomRange" />
        <input v-model="filters.end_at" class="filter-input" type="datetime-local" @input="markCustomRange" />
        <input v-model="filters.request_id" class="filter-input" type="text" placeholder="Request ID" />
        <input v-model="filters.route" class="filter-input" type="text" placeholder="Route" />
        <input v-model="filters.operation" class="filter-input" type="text" placeholder="Operation" />
        <select v-model="filters.status_code" class="filter-select">
          <option v-for="option in statusCodeOptions" :key="option.label" :value="option.value">{{ option.label }}</option>
        </select>
        <select v-model="filters.log_type" class="filter-select">
          <option v-for="option in logTypes" :key="option.label" :value="option.value">{{ option.label }}</option>
        </select>
        <select v-model="filters.level" class="filter-select">
          <option v-for="option in logLevels" :key="option.label" :value="option.value">{{ option.label }}</option>
        </select>
        <button class="action-btn primary" @click="applyFilters">查询</button>
        <button class="action-btn" @click="resetFilters">重置</button>
      </div>
    </div>

    <div class="log-list">
      <div v-if="loading && logs.length === 0" class="loading-state">
        <RefreshCw :size="20" class="spinning" />
        <span>加载中...</span>
      </div>

      <div v-else-if="errorMessage" class="empty-state error-state">
        <AlertCircle :size="32" />
        <span>{{ errorMessage }}</span>
      </div>

      <div v-else-if="logs.length === 0" class="empty-state">
        <Terminal :size="32" />
        <span>暂无日志</span>
      </div>

      <div v-else class="log-items">
        <div v-for="log in logs" :key="log.id" class="log-item">
          <div class="log-summary" @click="toggleDetails(log.id)">
            <div class="log-meta">
              <span class="log-type" :class="log.type">{{ typeLabels[log.type] || log.type }}</span>
              <span class="log-level" :style="{ color: levelColors[log.level] }">{{ log.level }}</span>
              <span v-if="log.duration_ms !== null" class="log-duration">{{ formatDuration(log.duration_ms) }}</span>
              <span v-if="log.status_code" class="log-status">HTTP {{ log.status_code }}</span>
            </div>
            <div class="log-message">{{ log.message }}</div>
            <div class="log-footer">
              <span v-if="log.source" class="log-source">{{ log.source }}</span>
              <span v-if="log.operation" class="log-operation">{{ log.operation }}</span>
              <span class="log-time">{{ formatTime(log.created_at) }}</span>
              <span class="log-expand">
                <ChevronDown v-if="expandedLogId === log.id" :size="14" />
                <ChevronRight v-else :size="14" />
              </span>
            </div>
          </div>
          <div v-if="expandedLogId === log.id" class="log-details">
            <div v-if="log.request_id" class="detail-row"><strong>Request ID:</strong> {{ log.request_id }}</div>
            <div v-if="log.route || log.method" class="detail-row"><strong>Route:</strong> {{ log.method || '-' }} {{ log.route || '-' }}</div>
            <div v-if="log.error_type" class="detail-row"><strong>Error:</strong> {{ log.error_type }}</div>
            <pre v-if="log.details" class="detail-json">{{ formatDetails(log.details) }}</pre>
          </div>
        </div>
      </div>
    </div>

    <div class="pagination">
      <div class="page-summary">共 {{ total }} 条 · 第 {{ filters.page }} / {{ totalPages }} 页</div>
      <div class="page-controls">
        <button class="page-btn" :disabled="filters.page === 1" @click="prevPage">上一页</button>
        <button
          v-for="page in visiblePageNumbers"
          :key="page"
          class="page-btn page-number"
          :class="{ active: page === filters.page }"
          @click="goToPage(page)"
        >
          {{ page }}
        </button>
        <button class="page-btn" :disabled="filters.page >= totalPages" @click="nextPage">下一页</button>
        <select class="filter-select page-size-select" :value="filters.page_size" @change="changePageSize(Number(($event.target as HTMLSelectElement).value))">
          <option v-for="size in pageSizeOptions" :key="size" :value="size">{{ size }}/页</option>
        </select>
      </div>
    </div>
  </div>
</template>

<style scoped>
.log-view {
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 24px;
  background: var(--bg-void);
}

.view-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.header-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 600;
  color: var(--accent-cyan);
}

.header-actions {
  display: flex;
  gap: 8px;
}

.btn-icon {
  padding: 8px;
  background: var(--bg-card);
  border: 1px solid var(--border-dim);
  border-radius: var(--radius-md);
  color: var(--text-dim);
  cursor: pointer;
  transition: all var(--transition-fast);
}

.btn-icon:hover, .btn-icon.active {
  background: var(--accent-cyan-dim);
  border-color: var(--accent-cyan);
  color: var(--accent-cyan);
}

.btn-icon .spinning {
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.stats-overview {
  display: flex;
  gap: 12px;
  margin-bottom: 20px;
}

.stat-card {
  flex: 1;
  background: var(--bg-card);
  border: 1px solid var(--border-dim);
  border-radius: var(--radius-md);
  padding: 12px 16px;
  text-align: center;
}

.stat-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  color: var(--text-dim);
  text-transform: uppercase;
  margin-bottom: 4px;
}

.stat-value {
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 600;
  color: var(--text-primary);
}

.stat-value.cyan { color: var(--accent-cyan); }
.stat-value.purple { color: var(--accent-purple); }
.stat-value.amber { color: var(--accent-amber); }
.stat-value.red { color: var(--accent-red); }

.filters {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 16px;
  padding: 12px 16px;
  background: var(--bg-card);
  border: 1px solid var(--border-dim);
  border-radius: var(--radius-md);
}

.toolbar-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

.filter-btn,
.filter-input,
.filter-select,
.action-btn,
.page-btn {
  border: 1px solid var(--border-dim);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 11px;
  transition: all var(--transition-fast);
}

.filter-btn,
.action-btn,
.page-btn {
  padding: 6px 12px;
  cursor: pointer;
}

.filter-btn.active,
.filter-btn:hover,
.action-btn:hover,
.page-btn:hover:not(:disabled),
.page-btn.active,
.filter-input:focus,
.filter-select:focus {
  border-color: var(--accent-cyan);
  color: var(--accent-cyan);
  outline: none;
}

.filter-btn.active,
.action-btn.primary,
.page-btn.active {
  background: var(--accent-cyan-dim);
}

.filter-input,
.filter-select {
  min-width: 120px;
  padding: 7px 10px;
}

.filter-input {
  color-scheme: dark;
}

.action-btn {
  background: var(--bg-void);
}

.log-list {
  flex: 1;
  overflow-y: auto;
  background: var(--bg-card);
  border: 1px solid var(--border-dim);
  border-radius: var(--radius-md);
}

.loading-state,
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 60px;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 12px;
}

.log-items {
  padding: 8px;
}

.log-item {
  border-bottom: 1px solid var(--border-dim);
  transition: background var(--transition-fast);
}

.log-summary {
  padding: 12px;
  cursor: pointer;
}

.log-item:last-child {
  border-bottom: none;
}

.log-item:hover {
  background: rgba(0, 245, 212, 0.02);
}

.log-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}

.log-type {
  font-family: var(--font-mono);
  font-size: 9px;
  padding: 2px 6px;
  border-radius: 4px;
  text-transform: uppercase;
}

.log-type.agent {
  background: rgba(0, 245, 212, 0.1);
  color: var(--accent-cyan);
}

.log-type.system {
  background: rgba(168, 85, 247, 0.1);
  color: var(--accent-purple);
}

.log-type.chat {
  background: rgba(249, 168, 37, 0.1);
  color: var(--accent-amber);
}

.log-level {
  font-family: var(--font-mono);
  font-size: 9px;
  text-transform: uppercase;
}

.log-duration {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-muted);
}

.log-message {
  font-size: 13px;
  color: var(--text-primary);
  line-height: 1.5;
  margin-bottom: 6px;
}

.log-footer {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-muted);
}

.log-status,
.log-operation,
.log-expand {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-muted);
}

.log-details {
  padding: 0 12px 12px;
  border-top: 1px solid var(--border-dim);
  background: rgba(255, 255, 255, 0.02);
}

.detail-row {
  margin-top: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-secondary);
}

.detail-json {
  margin-top: 10px;
  padding: 10px;
  background: var(--bg-void);
  border: 1px solid var(--border-dim);
  border-radius: var(--radius-sm);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-primary);
  white-space: pre-wrap;
}

.error-state {
  color: var(--accent-red);
}

.pagination {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  margin-top: 16px;
}

.page-summary {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-dim);
}

.page-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.page-number {
  min-width: 36px;
  padding-inline: 0;
}

.page-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.page-size-select {
  min-width: 90px;
}
</style>
