<script setup lang="ts">
import { onMounted, ref, computed } from 'vue'

import { useAuthStore } from '@/stores/auth'
import { fetchPreferences, createPreference, deletePreference, fetchRecommendedEvents } from '@/api/preferences'
import type { UserTopicPreference, MatchedEvent } from '@/types/preference'

const authStore = useAuthStore()
const userId = computed(() => authStore.user?.id ?? 0)

const preferences = ref<UserTopicPreference[]>([])
const newKeyword = ref('')
const loading = ref(true)
const submitting = ref(false)
const error = ref('')
const successMsg = ref('')

const matchedEvents = ref<MatchedEvent[]>([])
const loadingMatched = ref(false)
const matchedError = ref('')

const hoursRange = ref(72)
const sortBy = ref('match_score')

const hoursOptions = [
  { label: '24小时', value: 24 },
  { label: '72小时', value: 72 },
  { label: '7天', value: 168 },
]

const sortOptions = [
  { label: '匹配度', value: 'match_score' },
  { label: '最新', value: 'created_at' },
]

function onHoursChange(value: number) {
  hoursRange.value = value
  loadMatchedEvents()
}

function onSortChange(value: string) {
  sortBy.value = value
  loadMatchedEvents()
}

/** 加载用户的兴趣关键词 */
async function loadPreferences() {
  if (!userId.value) return
  loading.value = true
  error.value = ''
  try {
    preferences.value = await fetchPreferences(userId.value)
  } catch (e) {
    error.value = e instanceof Error ? e.message : '加载失败'
  } finally {
    loading.value = false
  }
}

/** 加载命中关键词的推荐事件 */
async function loadMatchedEvents() {
  if (!userId.value) return
  loadingMatched.value = true
  matchedError.value = ''
  try {
    const result = await fetchRecommendedEvents(userId.value, {
      limit: 30,
      hours: hoursRange.value,
      sort_by: sortBy.value
    })
    matchedEvents.value = result.data
  } catch (e) {
    matchedError.value = e instanceof Error ? e.message : '加载失败'
  } finally {
    loadingMatched.value = false
  }
}

/** 格式化热度标签 */
function hotLabel(score: number): { text: string; color: string; bg: string } {
  if (score >= 50) return { text: `🔥 ${score}`, color: '#ef4444', bg: 'rgba(239,68,68,0.1)' }
  if (score >= 20) return { text: `🌡 ${score}`, color: '#f59e0b', bg: 'rgba(245,158,11,0.1)' }
  return { text: `${score}`, color: 'var(--text-secondary)', bg: 'var(--bg-input)' }
}

/** 添加新关键词 */
async function handleAdd() {
  const keyword = newKeyword.value.trim()
  if (!keyword) return
  if (!userId.value) return

  submitting.value = true
  error.value = ''
  successMsg.value = ''
  try {
    const created = await createPreference(userId.value, keyword)
    preferences.value.unshift(created)
    newKeyword.value = ''
    successMsg.value = `已添加「${keyword}」`
    setTimeout(() => { successMsg.value = '' }, 3000)
    loadMatchedEvents()
  } catch (e) {
    error.value = e instanceof Error ? e.message : '添加失败'
  } finally {
    submitting.value = false
  }
}

/** 删除关键词 */
async function handleDelete(pref: UserTopicPreference) {
  if (!userId.value) return
  error.value = ''
  try {
    await deletePreference(userId.value, pref.id)
    preferences.value = preferences.value.filter(p => p.id !== pref.id)
    loadMatchedEvents()
  } catch (e) {
    error.value = e instanceof Error ? e.message : '删除失败'
  }
}

/** Enter 键提交 */
function onInputKeydown(e: KeyboardEvent) {
  if (e.key === 'Enter') {
    e.preventDefault()
    handleAdd()
  }
}

onMounted(async () => {
  await loadPreferences()
  loadMatchedEvents()
})
</script>

<template>
  <div class="topics-page">
    <div class="page-header">
      <h1>
        <i class="fa-solid fa-rss" style="color: var(--brand-primary)"></i>
        我的泛订阅
      </h1>
      <p class="page-desc">
        添加你感兴趣的关键词，系统会自动匹配全网热点事件并推送给你。
        支持精确匹配和 AI 语义匹配。
      </p>
    </div>

    <!-- 添加关键词 -->
    <div class="add-section">
      <div class="add-form">
        <div class="input-wrapper">
          <i class="fa-solid fa-plus input-icon"></i>
          <input
            v-model="newKeyword"
            type="text"
            class="keyword-input"
            placeholder="输入关键词，如「篮球」「科比」「科技」..."
            maxlength="100"
            @keydown="onInputKeydown"
          />
        </div>
        <button class="add-btn" :disabled="submitting || !newKeyword.trim()" @click="handleAdd">
          {{ submitting ? '添加中...' : '添加' }}
        </button>
      </div>

      <!-- 提示消息 -->
      <p v-if="successMsg" class="msg success-msg">
        <i class="fa-solid fa-check-circle"></i> {{ successMsg }}
      </p>
      <p v-if="error" class="msg error-msg">
        <i class="fa-solid fa-circle-exclamation"></i> {{ error }}
      </p>
    </div>

    <!-- 加载状态 -->
    <div v-if="loading" class="loading-state">
      <i class="fa-solid fa-spinner fa-spin"></i>
      <span>加载中...</span>
    </div>

    <!-- 关键词列表 -->
    <div v-else class="keywords-section">
      <h2 class="sub-title">
        已订阅的关键词
        <span class="count-badge">{{ preferences.length }}</span>
      </h2>

      <div v-if="preferences.length === 0" class="empty-state">
        <i class="fa-solid fa-bookmark"></i>
        <p>还没有添加任何关键词</p>
        <p class="empty-hint">在上方输入框中添加你感兴趣的话题</p>
      </div>

      <div v-else class="keywords-grid">
        <div v-for="pref in preferences" :key="pref.id" class="keyword-card">
          <div class="keyword-content">
            <i class="fa-solid fa-hashtag keyword-icon"></i>
            <span class="keyword-text">{{ pref.interested_keyword }}</span>
          </div>
          <button class="delete-btn" title="删除" @click="handleDelete(pref)">
            <i class="fa-solid fa-xmark"></i>
          </button>
        </div>
      </div>
    </div>

    <!-- 命中的热点事件 -->
    <div class="matched-section">
      <div class="section-header">
        <h2 class="sub-title">
          <i class="fa-solid fa-wand-magic-sparkles" style="color: var(--brand-primary)"></i>
          命中的热点事件
          <span v-if="!loadingMatched && matchedEvents.length > 0" class="count-badge">
            {{ matchedEvents.length }}
          </span>
        </h2>

        <!-- 筛选排序栏 -->
        <div v-if="preferences.length > 0" class="filters-bar">
          <div class="filter-group">
            <span class="filter-label">
              <i class="fa-regular fa-clock"></i> 时间范围
            </span>
            <div class="filter-tabs">
              <button
                v-for="opt in hoursOptions"
                :key="opt.value"
                class="filter-tab"
                :class="{ active: hoursRange === opt.value }"
                @click="onHoursChange(opt.value)"
              >
                {{ opt.label }}
              </button>
            </div>
          </div>

          <div class="filter-group">
            <span class="filter-label">
              <i class="fa-solid fa-arrow-down-wide-short"></i> 排序方式
            </span>
            <div class="filter-tabs">
              <button
                v-for="opt in sortOptions"
                :key="opt.value"
                class="filter-tab"
                :class="{ active: sortBy === opt.value }"
                @click="onSortChange(opt.value)"
              >
                {{ opt.label }}
              </button>
            </div>
          </div>
        </div>
      </div>

      <!-- 加载中 -->
      <div v-if="loadingMatched" class="loading-state">
        <i class="fa-solid fa-spinner fa-spin"></i>
        <span>AI 匹配中...</span>
      </div>

      <!-- 错误 -->
      <p v-else-if="matchedError" class="msg error-msg">
        <i class="fa-solid fa-circle-exclamation"></i> {{ matchedError }}
      </p>

      <!-- 无关键词 -->
      <div v-else-if="preferences.length === 0" class="empty-state">
        <i class="fa-solid fa-search"></i>
        <p>先添加关键词才能查看匹配事件</p>
      </div>

      <!-- 无匹配 -->
      <div v-else-if="matchedEvents.length === 0" class="empty-state">
        <i class="fa-solid fa-satellite-dish"></i>
        <p>暂未匹配到相关事件</p>
        <p class="empty-hint">系统会在下次 AI 摘要生成后自动更新</p>
      </div>

      <!-- 匹配事件列表 -->
      <div v-else class="matched-list">
        <RouterLink
          v-for="ev in matchedEvents"
          :key="ev.event_id"
          :to="{ path: '/', query: { event: ev.event_id } }"
          class="matched-card"
        >
          <!-- 热度 + 匹配度 -->
          <div class="matched-card-meta">
            <span
              class="hot-chip"
              :style="{ color: hotLabel(ev.hot_score).color, background: hotLabel(ev.hot_score).bg }"
            >
              {{ hotLabel(ev.hot_score).text }}
            </span>
            <span class="match-score-chip">
              <i class="fa-solid fa-crosshairs"></i>
              匹配度 {{ ev.match_score.toFixed(0) }}
            </span>
            <span class="matched-goto">
              <i class="fa-solid fa-arrow-up-right-from-square"></i> 查看详情
            </span>
          </div>

          <!-- 标题 -->
          <p class="matched-title">{{ ev.unified_title }}</p>

          <!-- AI 摘要 -->
          <p v-if="ev.summary" class="matched-summary">{{ ev.summary }}</p>

          <!-- 命中的关键词标签 -->
          <div class="matched-hits">
            <span v-for="hit in ev.exact_hits.slice(0, 4)" :key="hit" class="hit-tag exact">
              <i class="fa-solid fa-bullseye"></i> {{ hit }}
            </span>
            <span
              v-for="sh in ev.semantic_hits.slice(0, 3)"
              :key="sh.topic_keyword"
              class="hit-tag semantic"
            >
              <i class="fa-solid fa-brain"></i> {{ sh.topic_keyword }}
              <span class="sim-pct">{{ (sh.similarity * 100).toFixed(0) }}%</span>
            </span>
          </div>
        </RouterLink>
      </div>
    </div>

    <!-- 功能说明 -->
    <div class="info-panel">
      <h3><i class="fa-solid fa-lightbulb"></i> 匹配说明</h3>
      <ul>
        <li><strong>精确匹配：</strong>关键词与事件标签完全一致或互为包含关系时命中</li>
        <li><strong>语义匹配：</strong>使用向量模型计算语义相似度，超过阈值自动命中</li>
        <li><strong>推送触发：</strong>当新事件的标签命中您的关键词时，将在设定时间推送简报</li>
      </ul>
    </div>
  </div>
</template>

<style scoped>
.topics-page {
  max-width: 800px;
  margin: 0 auto;
}

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

.page-header h1 {
  font-size: 24px;
  font-weight: 700;
  margin: 0 0 8px;
  display: flex;
  align-items: center;
  gap: 10px;
}

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

/* ==========================================
   添加区域
========================================== */
.add-section {
  margin-bottom: 32px;
}

.add-form {
  display: flex;
  gap: 12px;
}

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

.input-icon {
  position: absolute;
  left: 14px;
  color: var(--text-placeholder);
  font-size: 13px;
}

.keyword-input {
  width: 100%;
  padding: 14px 16px 14px 42px;
  background: var(--bg-input);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font-size: 15px;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: inset 0 2px 4px rgba(0,0,0,0.02);
}

.keyword-input::placeholder {
  color: var(--text-placeholder);
}

.keyword-input:focus {
  outline: none;
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 4px var(--brand-primary-alpha), inset 0 1px 2px rgba(0,0,0,0.02);
  background: var(--bg-surface);
}

.add-btn {
  padding: 14px 28px;
  background: linear-gradient(135deg, var(--brand-primary) 0%, var(--brand-primary-hover) 100%);
  color: #fff;
  font-size: 15px;
  font-weight: 600;
  border-radius: var(--radius-md);
  white-space: nowrap;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 4px 12px var(--brand-primary-alpha);
}

.add-btn:hover:not(:disabled) {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px var(--brand-primary-alpha);
  filter: brightness(1.1);
}

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

.msg {
  font-size: 13px;
  margin: 10px 0 0;
  display: flex;
  align-items: center;
  gap: 6px;
}

.success-msg {
  color: var(--status-success);
}

.error-msg {
  color: var(--status-error);
}

/* ==========================================
   关键词列表
========================================== */
.keywords-section {
  margin-bottom: 32px;
}

.sub-title {
  font-size: 16px;
  font-weight: 600;
  margin: 0 0 16px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.count-badge {
  font-size: 12px;
  padding: 2px 10px;
  border-radius: 10px;
  background: var(--brand-primary-alpha);
  color: var(--brand-primary);
  font-weight: 700;
}

.loading-state {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 40px;
  color: var(--text-secondary);
}

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

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

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

.empty-hint {
  margin-top: 6px !important;
  font-size: 13px !important;
  color: var(--text-placeholder);
}

.keywords-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.keyword-card {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  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-lg);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: var(--shadow-sm);
}

.keyword-card:hover {
  border-color: var(--brand-primary-alpha);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.keyword-content {
  display: flex;
  align-items: center;
  gap: 6px;
}

.keyword-icon {
  color: var(--brand-primary);
  font-size: 12px;
}

.keyword-text {
  font-size: 14px;
  font-weight: 500;
}

.delete-btn {
  color: var(--text-placeholder);
  padding: 4px 6px;
  border-radius: 4px;
  font-size: 12px;
  transition: all 0.2s;
}

.delete-btn:hover {
  color: var(--status-error);
  background: rgba(239, 68, 68, 0.1);
}

/* ==========================================
   命中事件区块
========================================== */
.matched-section {
  margin-bottom: 32px;
}

.section-header {
  margin-bottom: 16px;
}

.section-header .sub-title {
  margin-bottom: 12px;
}

.filters-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  padding: 12px 16px;
  margin-bottom: 16px;
  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-lg);
  box-shadow: var(--shadow-sm);
}

.filter-group {
  display: flex;
  align-items: center;
  gap: 10px;
}

.filter-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 6px;
}

.filter-tabs {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  background: var(--bg-input);
  padding: 4px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-subtle);
}

.filter-tab {
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 600;
  border-radius: var(--radius-sm);
  border: none;
  background: transparent;
  color: var(--text-secondary);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  cursor: pointer;
}

.filter-tab:hover {
  color: var(--text-primary);
  background: var(--bg-hover);
}

.filter-tab.active {
  background: var(--bg-surface);
  color: var(--brand-primary);
  box-shadow: var(--shadow-sm);
}

.matched-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.matched-card {
  display: block;
  padding: 16px;
  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);
  text-decoration: none;
  color: inherit;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.matched-card:hover {
  border-color: var(--brand-primary-alpha);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.matched-card-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}

.hot-chip {
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 99px;
}

.match-score-chip {
  font-size: 11px;
  color: var(--text-placeholder);
  display: flex;
  align-items: center;
  gap: 4px;
}

.matched-goto {
  margin-left: auto;
  font-size: 11px;
  color: var(--brand-primary);
  opacity: 0;
  transition: opacity 0.2s;
  white-space: nowrap;
}

.matched-card:hover .matched-goto {
  opacity: 1;
}

.matched-title {
  font-size: 15px;
  font-weight: 600;
  line-height: 1.5;
  margin: 0 0 6px;
  color: var(--text-primary);
}

.matched-summary {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.6;
  margin: 0 0 8px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.matched-hits {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.hit-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 99px;
  font-size: 11px;
  font-weight: 600;
}

.hit-tag.exact {
  background: rgba(99, 102, 241, 0.1);
  color: #6366f1;
}

.hit-tag.semantic {
  background: rgba(16, 185, 129, 0.1);
  color: var(--status-success);
}

.sim-pct {
  opacity: 0.7;
}

/* ==========================================
   功能说明
========================================== */
.info-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);
  padding: 24px;
  box-shadow: var(--shadow-sm);
}

.info-panel h3 {
  font-size: 14px;
  font-weight: 600;
  margin: 0 0 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--text-primary);
}

.info-panel h3 i {
  color: #facc15;
}

.info-panel ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.info-panel li {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.8;
  padding-left: 16px;
  position: relative;
}

.info-panel li::before {
  content: '•';
  position: absolute;
  left: 0;
  color: var(--brand-primary);
}
</style>
