<script setup lang="ts">
import { ref, computed } from 'vue'
import VueApexCharts from 'vue3-apexcharts'
import { searchEventsTimeline } from '@/api/events'
import type { SearchTimelineResponse } from '@/types/event'
import UnifiedEventCard from '@/components/UnifiedEventCard.vue'
import CustomSelect from '@/components/CustomSelect.vue'
import type { ApexOptions } from 'apexcharts'

const keyword = ref('')
const searchResult = ref<SearchTimelineResponse | null>(null)
const loading = ref(false)
const hours = ref(2)
const searchMode = ref<'exact' | 'semantic' | 'hybrid'>('exact')
const selectedTimeLabel = ref<string | null>(null)

const timeOptions = [
  { label: '最近 2 小时', value: 2 },
  { label: '最近 12 小时', value: 12 },
  { label: '最近 24 小时', value: 24 },
  { label: '最近 48 小时', value: 48 },
  { label: '最近 7 天', value: 168 },
  { label: '最近 15 天', value: 360 }
]

const modeOptions = [
  { label: '混合匹配', value: 'hybrid' },
  { label: '关键词匹配', value: 'exact' },
  { label: '语义匹配', value: 'semantic' }
]

// 根据选中的时间点筛选事件：点击图表节点时只显示该时间点关联的事件
const filteredEvents = computed(() => {
  if (!searchResult.value) return []
  if (!selectedTimeLabel.value) return searchResult.value.events

  const selectedPoint = searchResult.value.timeline.find(p => p.time_label === selectedTimeLabel.value)
  if (!selectedPoint) return []

  const pointEventIds = selectedPoint.event_ids ?? []
  if (pointEventIds.length > 0) {
    const relatedIds = new Set(pointEventIds)
    return searchResult.value.events.filter(event => relatedIds.has(event.event_id))
  }

  // 向后兼容：旧版后端未返回 event_ids 时，退化为时间范围过滤。
  return searchResult.value.events.filter(event => {
    const createdStr = event.created_at.replace('T', ' ')
    const activeStr = event.last_active_at.replace('T', ' ')
    const len = selectedTimeLabel.value!.length
    const start = createdStr.substring(0, len)
    const end = activeStr.substring(0, len)
    const target = selectedTimeLabel.value!
    return (start <= target && target <= end) || createdStr.startsWith(target) || activeStr.startsWith(target)
  })
})

// 热度时间线图表配置。
const chartOptions = ref<ApexOptions>({
  chart: {
    type: 'area',
    height: 350,
    background: 'transparent',
    toolbar: {
      show: true
    },
    animations: {
      enabled: true,
      // easing: 'easeinout',
      speed: 800,
    },
    // 点击图表数据点：切换选中时间，再次点击则取消筛选
    events: {
      mounted: (chartContext: any) => {
        chartContext.el?.querySelector('.apexcharts-svg > title')?.remove()
      },
      updated: (chartContext: any) => {
        chartContext.el?.querySelector('.apexcharts-svg > title')?.remove()
      },
      markerClick: function(event: unknown, chartContext: unknown, { dataPointIndex }: never) {
        if (searchResult.value && searchResult.value.timeline[dataPointIndex]) {
          const clickedTime = searchResult.value.timeline[dataPointIndex].time_label
          if (selectedTimeLabel.value === clickedTime) {
            selectedTimeLabel.value = null
          } else {
            selectedTimeLabel.value = clickedTime
            // 点击时间点后平滑滚动到事件列表。
            setTimeout(() => {
              document.getElementById('events-section-anchor')?.scrollIntoView({ behavior: 'smooth' })
            }, 100)
          }
        }
      }
    }
  },
  theme: {
    mode: 'dark' // 默认使用暗色图表主题，保证深浅主题下对比度都清晰。
  },
  dataLabels: {
    enabled: false
  },
  stroke: {
    curve: 'smooth',
    width: 3
  },
  xaxis: {
    type: 'category',
    categories: [] as string[],
    labels: {
      style: {
        colors: '#9ca3af'
      }
    },
    axisBorder: {
      show: false
    },
    axisTicks: {
      show: false
    }
  },
  yaxis: {
    title: {
      text: '热点数量',
      style: {
        color: '#9ca3af',
        fontWeight: 500
      }
    },
    labels: {
      style: {
        colors: '#9ca3af'
      }
    }
  },
  fill: {
    type: 'gradient',
    gradient: {
      shadeIntensity: 1,
      opacityFrom: 0.6,
      opacityTo: 0.1,
      stops: [0, 90, 100]
    }
  },
  grid: {
    borderColor: 'rgba(156, 163, 175, 0.1)',
    strokeDashArray: 4,
  },
  colors: ['#6366f1'],
  tooltip: {
    theme: 'dark'
  }
})

const series = ref([{
  name: '热点分布',
  data: [] as number[]
}])

async function handleSearch() {
  if (!keyword.value.trim()) return

  loading.value = true
  searchResult.value = null
  selectedTimeLabel.value = null
  try {
    const res = await searchEventsTimeline(keyword.value.trim(), hours.value, searchMode.value)
    searchResult.value = res

    // 查询成功后同步刷新图表横轴与序列。
    chartOptions.value = {
      ...chartOptions.value,
      xaxis: {
        ...chartOptions.value.xaxis,
        categories: res.timeline.map(p => p.time_label)
      }
    }
    series.value = [{
      name: '热点数量',
      data: res.timeline.map(p => p.count)
    }]
  } catch (error) {
    console.error('搜索失败', error)
  } finally {
    loading.value = false
  }
}
</script>

<template>
  <div class="search-view">
    <div class="content-wrapper">
      <header class="page-header">
        <div class="header-title-row">
          <h1 class="page-title">
            <i class="fa-solid fa-chart-line" style="color: var(--brand-primary)"></i>
            事件追踪分析
          </h1>
        </div>
        <p class="page-desc">基于语义匹配与正则检索，分析关键词在时间维度上的热度变化与关联聚合事件。</p>
      </header>

      <div class="top-panels">
        <div class="search-box glass-panel">
          <h2 class="panel-title"><i class="fa-solid fa-magnifying-glass-chart"></i> 关键词搜索</h2>
          <div class="search-controls">
            <div class="input-wrapper">
              <i class="fa-solid fa-magnifying-glass search-icon"></i>
              <input
                v-model="keyword"
                @keyup.enter="handleSearch"
                type="text"
                placeholder="请输入关键词"
                class="search-input"
              />
            </div>
            <CustomSelect
              v-model="hours"
              :options="timeOptions"
              icon="fa-regular fa-clock"
            />
            <CustomSelect
              v-model="searchMode"
              :options="modeOptions"
              icon="fa-solid fa-filter"
            />
            <button class="btn btn-primary" @click="handleSearch" :disabled="loading || !keyword.trim()">
              <i class="fa-solid fa-bolt" v-if="!loading"></i>
              <i class="fa-solid fa-spinner fa-spin" v-else></i>
              追踪计算
            </button>
          </div>
        </div>

        <div class="tips-box glass-panel">
          <h2 class="panel-title"><i class="fa-regular fa-lightbulb"></i> 搜索建议</h2>
          <div class="tips-content">
            <button class="tip-tag" @click="keyword='火箭发射'; hours=168; handleSearch()">
              <i class="fa-solid fa-rocket"></i> 火箭发射
            </button>
            <button class="tip-tag" @click="keyword='苹果公司'; hours=168; handleSearch()">
              <i class="fa-brands fa-apple"></i> 苹果公司
            </button>
            <button class="tip-tag regex-tag" @click="keyword='AI|LLM'; hours=168; handleSearch()">
              <i class="fa-solid fa-code-branch"></i> AI / 大模型
            </button>
            <button class="tip-tag regex-tag" @click="keyword='美国'; hours=168; handleSearch()">
              <i class="fa-solid fa-flag-usa"></i> 美国
            </button>
          </div>
        </div>
      </div>

      <div v-if="loading" class="loading-state glass-panel">
        <div class="spinner-wrapper">
          <i class="fa-solid fa-circle-notch fa-spin"></i>
        </div>
        <p>引擎正在计算热度模型并提取时间节点，请稍候...</p>
      </div>

      <div v-else-if="searchResult" class="results-container">
        <section class="chart-section glass-panel">
          <div class="section-header">
            <div class="section-title-group">
              <h2 class="section-title">
                <i class="fa-solid fa-wave-square"></i> 时间热度脉络
              </h2>
              <span class="chart-tip">
                <i class="fa-solid fa-hand-pointer"></i>
                点击时间点查看具体事件列表
              </span>
            </div>
            <span class="meta-info">共 {{ searchResult.timeline.length }} 个时间节点 · 覆盖 {{ searchResult.events.length }} 个聚合事件</span>
          </div>

          <div class="chart-container" v-if="searchResult.timeline.length > 0">
            <VueApexCharts
              type="area"
              height="350"
              :options="chartOptions"
              :series="series"
            />
          </div>
          <div v-else class="empty-state">
            <i class="fa-regular fa-folder-open"></i>
            <p>该时间范围暂无热度节点</p>
          </div>
        </section>

        <section id="events-section-anchor" class="events-section">
          <div class="section-header">
            <h2 class="section-title">
              <i class="fa-solid fa-layer-group"></i> 关联深度聚合事件
              <span v-if="selectedTimeLabel" class="time-filter-badge">
                筛选: {{ selectedTimeLabel }}
                <i class="fa-solid fa-xmark" @click="selectedTimeLabel = null"></i>
              </span>
            </h2>
            <span class="meta-info">共检索到 {{ filteredEvents.length }} 个聚合事件</span>
          </div>
          <div class="events-grid" v-if="filteredEvents.length > 0">
            <UnifiedEventCard
              v-for="event in filteredEvents"
              :key="event.event_id"
              :event="event"
            />
          </div>
          <div v-else class="empty-state glass-panel">
            <i class="fa-solid fa-satellite-dish"></i>
            <p v-if="selectedTimeLabel">该时间点未找到匹配事件，请尝试点击其他节点</p>
            <p v-else>暂无关联聚合事件，可尝试扩大时间范围或更换关键词</p>
          </div>
        </section>
      </div>
    </div>
  </div>
</template>

<style scoped>
.search-view {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
}

.content-wrapper {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.page-header {
  margin-bottom: 8px;
}

.header-title-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}

.page-title {
  font-size: 24px;
  font-weight: 700;
  color: var(--text-color);
  margin: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  letter-spacing: 0.02em;
}

.page-desc {
  color: var(--text-secondary);
  font-size: 14px;
  margin: 0;
  font-weight: 500;
}

/* 毛玻璃面板 */
.glass-panel {
  background: var(--bg-surface);
  backdrop-filter: var(--backdrop-blur);
  -webkit-backdrop-filter: var(--backdrop-blur);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-sm);
  padding: 24px;
  transition: all 0.3s ease;
}

.glass-panel:hover {
  box-shadow: var(--shadow-md);
  border-color: rgba(99, 102, 241, 0.2);
}

.top-panels {
  display: flex;
  gap: 24px;
  align-items: stretch;
  position: relative;
  z-index: 10;
}

.search-box {
  flex: 2;
  padding: 24px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  position: relative;
  z-index: 2;
}

.tips-box {
  flex: 1;
  padding: 24px;
  display: flex;
  flex-direction: column;
  position: relative;
  z-index: 1;
}

.panel-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--text-color);
  margin: 0 0 20px 0;
  display: flex;
  align-items: center;
  gap: 8px;
}

.panel-title i {
  color: var(--brand-primary);
}

.tips-content {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.tip-tag {
  background: var(--bg-input);
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  padding: 8px 14px;
  border-radius: var(--radius-lg);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.tip-tag i {
  font-size: 14px;
  opacity: 0.8;
}

.tip-tag:hover {
  background: var(--brand-primary-alpha);
  color: var(--brand-primary);
  border-color: var(--brand-primary);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(99, 102, 241, 0.15);
}

.tip-tag.regex-tag {
  border-style: dashed;
}

.search-controls {
  display: flex;
  gap: 16px;
  align-items: center;
  flex-wrap: wrap;
}

.input-wrapper {
  flex: 1;
  min-width: 250px;
  position: relative;
  display: flex;
  align-items: center;
}

.search-icon {
  position: absolute;
  left: 16px;
  color: var(--text-placeholder);
  font-size: 16px;
  z-index: 1;
}

.search-input {
  width: 100%;
  padding: 14px 16px 14px 44px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background-color: var(--bg-input);
  color: var(--text-primary);
  font-size: 15px;
  font-weight: 500;
  transition: all 0.2s;
}

.search-input:focus {
  outline: none;
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px var(--brand-primary-alpha);
  background-color: var(--bg-surface);
}

.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 14px 28px;
  background-color: var(--brand-primary);
  color: white;
  border: none;
  border-radius: var(--radius-lg);
  font-weight: 600;
  font-size: 15px;
  cursor: pointer;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
}

.btn-primary:hover:not(:disabled) {
  background-color: var(--brand-primary-hover);
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(99, 102, 241, 0.3);
}

.btn-primary:active:not(:disabled) {
  transform: translateY(1px);
}

.btn-primary:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  box-shadow: none;
}

.results-container {
  display: flex;
  flex-direction: column;
  gap: 24px;
  animation: fadeIn 0.4s ease-out;
  position: relative;
  z-index: 1; /* 低于 top-panels，避免图表覆盖搜索框下拉 */
}

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

.section-title {
  font-size: 18px;
  font-weight: 700;
  color: var(--text-color);
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
}

.section-title i {
  color: var(--brand-primary);
}

.section-title-group {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.chart-tip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: var(--radius-md);
  background: var(--brand-primary-alpha);
  border: 1px solid rgba(99, 102, 241, 0.2);
  color: var(--brand-primary);
  font-size: 12px;
  font-weight: 600;
}

.chart-tip i {
  font-size: 12px;
}

.time-filter-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 12px;
  padding: 4px 10px;
  background: rgba(99, 102, 241, 0.15);
  color: var(--brand-primary);
  border-radius: var(--radius-full);
  font-size: 13px;
  font-weight: 500;
  vertical-align: middle;
}

.time-filter-badge i {
  cursor: pointer;
  font-size: 14px;
  color: var(--brand-primary) !important;
  opacity: 0.7;
  transition: opacity 0.2s;
}

.time-filter-badge i:hover {
  opacity: 1;
}

.meta-info {
  font-size: 13px;
  color: var(--text-secondary);
  font-weight: 500;
}

.chart-section {
  padding: 24px;
}

.chart-container {
  margin-top: 16px;
  margin-left: -10px;
}

.chart-container :deep(svg),
.chart-container :deep(canvas) {
  outline: none;
}

.chart-container :deep(.apexcharts-marker) {
  cursor: pointer;
}

.events-section {
  margin-top: 8px;
}

.events-grid {
  display: flex;
  flex-direction: column;
}

.loading-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 20px;
  color: var(--text-secondary);
  gap: 16px;
}

.spinner-wrapper {
  font-size: 32px;
  color: var(--brand-primary);
}

.loading-state p {
  font-size: 15px;
  font-weight: 500;
}

.empty-state {
  text-align: center;
  padding: 40px 20px;
  color: var(--text-secondary);
}

.empty-state i {
  font-size: 36px;
  opacity: 0.4;
  margin-bottom: 12px;
  display: block;
}

.empty-state p {
  font-size: 14px;
  margin: 0;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (max-width: 768px) {
  .top-panels {
    flex-direction: column;
  }
}

@media (max-width: 640px) {
  .search-controls {
    flex-direction: column;
    align-items: stretch;
  }

  .btn-primary {
    justify-content: center;
  }

  .section-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
}
</style>
