<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { fetchAgentOssLogs } from '../api/ossLog'
import type { OssLogItem } from '../types/ossLog'

const items = ref<OssLogItem[]>([])
const agents = ref<string[]>([])
const selectedAgent = ref('')
const keyword = ref('')
const loading = ref(true)
const error = ref<string | null>(null)
let requestId = 0

const filteredItems = computed(() => {
  const query = keyword.value.trim().toLocaleLowerCase()
  if (!query) return items.value
  return items.value.filter((item) =>
    [item.log_name, item.agent_name, item.oss_path]
      .filter(Boolean)
      .join(' ')
      .toLocaleLowerCase()
      .includes(query),
  )
})

onMounted(() => loadLogs())

watch(selectedAgent, () => loadLogs(selectedAgent.value))

async function loadLogs(agentName?: string) {
  const currentRequest = ++requestId
  loading.value = true
  error.value = null
  try {
    const data = await fetchAgentOssLogs(agentName || null)
    if (currentRequest !== requestId) return
    items.value = data.items ?? []
    if (data.agents?.length) agents.value = data.agents
  } catch (e) {
    if (currentRequest !== requestId) return
    error.value = e instanceof Error ? e.message : String(e)
  } finally {
    if (currentRequest === requestId) loading.value = false
  }
}

function openHtml(item: OssLogItem) {
  const url = item.oss_path?.trim()
  if (!url) return
  window.open(url, '_blank', 'noopener,noreferrer')
}

function displayAgentName(value: string | null): string {
  if (!value) return '未标记 Agent'
  return value.replace(/_agent$/, '').replaceAll('_', ' ')
}

function formatTime(value: string | null): string {
  if (!value) return '—'
  const date = new Date(value)
  if (Number.isNaN(date.getTime())) return value
  return new Intl.DateTimeFormat('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false,
  }).format(date)
}

function agentTone(value: string | null): string {
  if (!value) return 'tone-gray'
  if (value.includes('find')) return 'tone-orange'
  if (value.includes('grade')) return 'tone-violet'
  if (value.includes('belong')) return 'tone-blue'
  if (value.includes('expand')) return 'tone-green'
  if (value.includes('generate')) return 'tone-cyan'
  return 'tone-gray'
}
</script>

<template>
  <div class="audit-page">
    <header class="audit-header">
      <div>
        <div class="eyebrow"><span /> AGENT TRACEABILITY</div>
        <h1>Agent 运行审计</h1>
        <p>查看模型输入、思考过程、工具调用与完整运行结果。</p>
      </div>
      <div class="header-stat">
        <strong>{{ filteredItems.length }}</strong>
        <span>{{ selectedAgent ? '筛选结果' : '全部记录' }}</span>
      </div>
    </header>

    <section class="filter-bar" aria-label="日志筛选">
      <label class="agent-select">
        <span class="filter-label">指定 Agent</span>
        <span class="select-wrap">
          <i class="agent-dot" :class="agentTone(selectedAgent)" />
          <select v-model="selectedAgent" aria-label="选择 Agent">
            <option value="">全部 Agent</option>
            <option v-for="agent in agents" :key="agent" :value="agent">
              {{ displayAgentName(agent) }}
            </option>
          </select>
        </span>
      </label>

      <label class="search-control">
        <span class="search-icon" aria-hidden="true" />
        <input
          v-model="keyword"
          type="search"
          placeholder="搜索日志名称或 OSS 路径"
          aria-label="搜索日志"
        />
        <button v-if="keyword" type="button" aria-label="清空搜索" @click="keyword = ''">×</button>
      </label>

      <button class="refresh-button" type="button" :disabled="loading" @click="loadLogs(selectedAgent)">
        <span :class="{ spinning: loading }">↻</span>
        刷新
      </button>
    </section>

    <div v-if="error" class="state error">
      <strong>日志加载失败</strong>
      <span>{{ error }}</span>
      <button type="button" @click="loadLogs(selectedAgent)">重新加载</button>
    </div>

    <section v-else class="table-card">
      <div class="table-headline">
        <span>
          {{ selectedAgent ? displayAgentName(selectedAgent) : '全部 Agent' }}
          <b>{{ filteredItems.length }}</b>
        </span>
        <small>按创建时间倒序 · 点击记录打开 HTML 审计详情</small>
      </div>

      <div v-if="loading" class="state">
        <span class="loader" />
        正在加载审计记录…
      </div>

      <div v-else-if="!filteredItems.length" class="state empty">
        <span class="empty-icon">◎</span>
        <strong>{{ keyword ? '没有匹配的日志' : '暂无审计记录' }}</strong>
        <small>{{ keyword ? '尝试更换关键词或 Agent' : 'Agent 执行后，日志会出现在这里' }}</small>
      </div>

      <div v-else class="table-wrap">
        <table>
          <thead>
            <tr>
              <th class="col-time">创建时间</th>
              <th class="col-agent">Agent</th>
              <th class="col-name">日志名称</th>
              <th class="col-path">OSS 审计文件</th>
              <th class="col-open" aria-label="打开" />
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="item in filteredItems"
              :key="item.id"
              class="row"
              tabindex="0"
              @click="openHtml(item)"
              @keydown.enter="openHtml(item)"
            >
              <td class="time">{{ formatTime(item.create_time) }}</td>
              <td>
                <span class="agent-badge" :class="agentTone(item.agent_name)">
                  <i />
                  {{ displayAgentName(item.agent_name) }}
                </span>
              </td>
              <td class="name">{{ item.log_name || '未命名日志' }}</td>
              <td class="path" :title="item.oss_path || ''">{{ item.oss_path || '—' }}</td>
              <td class="open-arrow">↗</td>
            </tr>
          </tbody>
        </table>
      </div>
    </section>
  </div>
</template>

<style scoped>
.audit-page {
  display: flex;
  min-height: 100%;
  flex-direction: column;
  gap: 18px;
  color: #202738;
}

.audit-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  padding: 10px 4px 4px;
}

.eyebrow {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #71798b;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.17em;
}

.eyebrow span {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #6666d4;
  box-shadow: 0 0 0 4px rgba(102, 102, 212, 0.11);
}

.audit-header h1 {
  margin: 9px 0 5px;
  font-size: 28px;
  letter-spacing: -0.04em;
}

.audit-header p {
  margin: 0;
  color: #858c9b;
  font-size: 12px;
}

.header-stat {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 0 4px;
}

.header-stat strong {
  font-size: 28px;
  letter-spacing: -0.05em;
}

.header-stat span {
  color: #959ba8;
  font-size: 10px;
}

.filter-bar {
  display: flex;
  min-height: 68px;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border: 1px solid #e5e7ec;
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.88);
}

.agent-select {
  display: flex;
  min-width: 270px;
  align-items: center;
  gap: 11px;
}

.filter-label {
  color: #7e8594;
  font-size: 10px;
  font-weight: 700;
  white-space: nowrap;
}

.select-wrap {
  position: relative;
  flex: 1;
}

.select-wrap select {
  width: 100%;
  height: 40px;
  padding: 0 34px 0 31px;
  border: 1px solid #dfe2e8;
  border-radius: 9px;
  appearance: none;
  outline: none;
  background:
    linear-gradient(45deg, transparent 50%, #8d94a2 50%) calc(100% - 17px) 17px / 5px 5px no-repeat,
    linear-gradient(135deg, #8d94a2 50%, transparent 50%) calc(100% - 12px) 17px / 5px 5px no-repeat,
    #fff;
  color: #3f4758;
  font-size: 11px;
  font-weight: 600;
}

.select-wrap select:focus {
  border-color: #7777d8;
  box-shadow: 0 0 0 3px rgba(102, 102, 212, 0.09);
}

.agent-dot {
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 13px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  transform: translateY(-50%);
}

.search-control {
  position: relative;
  flex: 1;
}

.search-control input {
  width: 100%;
  height: 40px;
  padding: 0 36px 0 39px;
  border: 1px solid #dfe2e8;
  border-radius: 9px;
  outline: none;
  background: #fff;
  color: #3f4758;
  font-size: 11px;
}

.search-control input:focus {
  border-color: #7777d8;
  box-shadow: 0 0 0 3px rgba(102, 102, 212, 0.09);
}

.search-control input::placeholder {
  color: #a6acb7;
}

.search-icon {
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 15px;
  width: 12px;
  height: 12px;
  border: 1.5px solid #8f96a5;
  border-radius: 50%;
  transform: translateY(-58%);
}

.search-icon::after {
  position: absolute;
  right: -4px;
  bottom: -3px;
  width: 5px;
  height: 1.5px;
  background: #8f96a5;
  content: '';
  transform: rotate(45deg);
}

.search-control button {
  position: absolute;
  top: 50%;
  right: 10px;
  width: 24px;
  height: 24px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: #949aa7;
  cursor: pointer;
  transform: translateY(-50%);
}

.refresh-button {
  display: inline-flex;
  height: 40px;
  align-items: center;
  gap: 7px;
  padding: 0 14px;
  border: 1px solid #dfe2e8;
  border-radius: 9px;
  background: #fff;
  color: #687082;
  font-size: 10px;
  font-weight: 700;
  cursor: pointer;
}

.refresh-button:disabled {
  cursor: wait;
  opacity: 0.58;
}

.spinning {
  animation: spin 0.75s linear infinite;
}

.table-card {
  display: flex;
  min-height: 360px;
  flex: 1;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid #e4e7ed;
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.94);
  box-shadow: 0 12px 35px rgba(35, 42, 60, 0.035);
}

.table-headline {
  display: flex;
  min-height: 55px;
  align-items: center;
  justify-content: space-between;
  padding: 0 18px;
  border-bottom: 1px solid #eceef2;
}

.table-headline span {
  font-size: 11px;
  font-weight: 700;
}

.table-headline b {
  display: inline-flex;
  min-width: 23px;
  height: 19px;
  align-items: center;
  justify-content: center;
  margin-left: 7px;
  padding: 0 6px;
  border-radius: 999px;
  background: #eeeeff;
  color: #6262ce;
  font-size: 9px;
}

.table-headline small {
  color: #9ba1ad;
  font-size: 9px;
}

.table-wrap {
  flex: 1;
  overflow: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  font-size: 11px;
}

th,
td {
  height: 52px;
  padding: 0 15px;
  border-bottom: 1px solid #f0f1f4;
  text-align: left;
  vertical-align: middle;
}

th {
  position: sticky;
  z-index: 1;
  top: 0;
  height: 40px;
  background: #fafafd;
  color: #8d94a3;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.03em;
}

.col-time { width: 174px; }
.col-agent { width: 210px; }
.col-name { width: 260px; }
.col-open { width: 44px; }

.row {
  outline: none;
  cursor: pointer;
  transition: background 0.14s;
}

.row:hover,
.row:focus {
  background: #f8f8fc;
}

.time {
  color: #727a89;
  font-variant-numeric: tabular-nums;
}

.agent-badge {
  display: inline-flex;
  max-width: 100%;
  height: 25px;
  align-items: center;
  gap: 7px;
  overflow: hidden;
  padding: 0 9px;
  border-radius: 7px;
  background: var(--tone-soft);
  color: var(--tone);
  font-size: 9px;
  font-weight: 700;
  text-overflow: ellipsis;
  text-transform: capitalize;
  white-space: nowrap;
}

.agent-badge i {
  width: 6px;
  height: 6px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--tone);
}

.tone-blue { --tone: #4d75c8; --tone-soft: #eaf1ff; background: var(--tone, #4d75c8); }
.tone-violet { --tone: #7560c8; --tone-soft: #f0ecff; background: var(--tone, #7560c8); }
.tone-orange { --tone: #c5793d; --tone-soft: #fff0e2; background: var(--tone, #c5793d); }
.tone-green { --tone: #2b9272; --tone-soft: #e5f7f0; background: var(--tone, #2b9272); }
.tone-cyan { --tone: #308ba1; --tone-soft: #e4f5f8; background: var(--tone, #308ba1); }
.tone-gray { --tone: #7d8492; --tone-soft: #eef0f3; background: var(--tone, #7d8492); }

.agent-badge.tone-blue,
.agent-badge.tone-violet,
.agent-badge.tone-orange,
.agent-badge.tone-green,
.agent-badge.tone-cyan,
.agent-badge.tone-gray {
  background: var(--tone-soft);
}

.name {
  overflow: hidden;
  color: #333b4c;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.path {
  overflow: hidden;
  color: #89909e;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 9px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.open-arrow {
  color: #a4aab5;
  font-size: 14px;
}

.state {
  display: flex;
  min-height: 280px;
  align-items: center;
  justify-content: center;
  gap: 10px;
  flex: 1;
  color: #838a99;
  font-size: 11px;
}

.state.error {
  min-height: 260px;
  flex-direction: column;
  border: 1px solid #f0d9d7;
  border-radius: 16px;
  background: #fff7f6;
  color: #a95752;
}

.state.error strong {
  font-size: 13px;
}

.state.error button {
  margin-top: 6px;
  padding: 7px 12px;
  border: 1px solid #e3b9b6;
  border-radius: 7px;
  background: #fff;
  color: #a95752;
  cursor: pointer;
}

.state.empty {
  flex-direction: column;
}

.state.empty .empty-icon {
  color: #7373d5;
  font-size: 28px;
}

.state.empty strong {
  color: #636b7b;
}

.state.empty small {
  color: #a1a7b2;
  font-size: 9px;
}

.loader {
  width: 15px;
  height: 15px;
  border: 2px solid #dddff0;
  border-top-color: #6666d4;
  border-radius: 50%;
  animation: spin 0.75s linear infinite;
}

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

@media (max-width: 760px) {
  .audit-header {
    align-items: flex-start;
    flex-direction: column;
    gap: 14px;
  }

  .filter-bar {
    align-items: stretch;
    flex-direction: column;
  }

  .agent-select {
    min-width: 0;
    align-items: flex-start;
    flex-direction: column;
  }

  .select-wrap {
    width: 100%;
  }

  .table-headline {
    align-items: flex-start;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
  }

  .table-wrap {
    overflow-x: auto;
  }

  table {
    min-width: 930px;
  }
}

/* Readability and contrast */
.eyebrow {
  color: #5f6878;
  font-size: 11px;
}

.audit-header p,
.header-stat span,
.filter-label {
  color: #5f6878;
  font-size: 12px;
}

.select-wrap select,
.search-control input {
  color: #30394a;
  font-size: 13px;
}

.refresh-button,
.table-headline span,
.state {
  color: #4b5565;
  font-size: 12px;
}

.table-headline small,
th {
  color: #667085;
  font-size: 11px;
}

table {
  font-size: 13px;
}

.agent-badge,
.path {
  font-size: 11px;
}

.time {
  color: #4f5969;
}

.path {
  color: #5f6878;
}

.state.empty small {
  color: #667085;
  font-size: 11px;
}
</style>
