<script setup lang="ts">
import { request } from '~/utils/http/factory'

definePageMeta({ layout: 'home' })

const { $toast } = useNuxtApp()
const { loggedIn } = useAuthSession()
const router = useRouter()

// ── Types ──

interface CardRef {
  id: number
  title: string
  type: string
  coverUrl: string | null
  sortOrder: number
}

interface ArticleItem {
  id: number
  title: string
  content: string
  summary: string | null
  cover: string | null
  status: 'draft' | 'published'
  createdAt: Date
  updatedAt: Date
  cards: CardRef[]
}

interface ListResult {
  items: ArticleItem[]
  total: number
  page: number
  pageSize: number
  hasMore: boolean
}

// ── State ──

const articles = ref<ArticleItem[]>([])
const loading = ref(true)
const total = ref(0)
const page = ref(1)
const pageSize = 12
const hasMore = ref(false)
const statusFilter = ref<'draft' | 'published' | ''>('')
const searchQuery = ref('')

// ── Article form dialog ──

const dialogVisible = ref(false)
const dialogMode = ref<'create' | 'edit'>('create')
const dialogArticle = ref<ArticleItem | null>(null)

// ── Confirm dialog ──

const confirmShow = ref(false)
const confirmMsg = ref('')
let confirmAction: (() => void) | null = null

function showConfirm(msg: string, action: () => void) {
  confirmMsg.value = msg
  confirmAction = action
  confirmShow.value = true
}

function onConfirm() {
  confirmAction?.()
  confirmShow.value = false
}

// ── Data fetching ──

async function fetchArticles() {
  loading.value = true
  try {
    const params = new URLSearchParams()
    params.set('page', String(page.value))
    params.set('pageSize', String(pageSize))
    if (statusFilter.value) params.set('status', statusFilter.value)
    if (searchQuery.value) params.set('q', searchQuery.value)

    const raw = await request<{ code: number; data: ListResult }>(
      `/api/articles?${params.toString()}`,
    )
    articles.value = raw.data.items
    total.value = raw.data.total
    hasMore.value = raw.data.hasMore
  } catch {
    $toast.error('文章加载失败')
  } finally {
    loading.value = false
  }
}

// ── Actions ──

function openCreate() {
  dialogMode.value = 'create'
  dialogArticle.value = null
  dialogVisible.value = true
}

function openEdit(article: ArticleItem) {
  dialogMode.value = 'edit'
  dialogArticle.value = article
  dialogVisible.value = true
}

function onArticleSaved() {
  fetchArticles()
}

async function handleDelete(id: number) {
  try {
    await request(`/api/articles/${id}`, { method: 'DELETE' })
    $toast.success('文章已删除')
    await fetchArticles()
  } catch (e: any) {
    $toast.error(e?.data?.message || e?.message || '删除失败')
  }
}

function goDetail(id: number) {
  router.push(`/articles/${id}`)
}

function onPageChange(dir: -1 | 1) {
  const np = page.value + dir
  if (np < 1) return
  page.value = np
  fetchArticles()
}

// ── Filters ──

watch(statusFilter, () => {
  page.value = 1
  fetchArticles()
})

// ── Search debounce ──

let searchTimer: ReturnType<typeof setTimeout> | null = null
function onSearchInput() {
  if (searchTimer) clearTimeout(searchTimer)
  searchTimer = setTimeout(() => {
    page.value = 1
    fetchArticles()
  }, 400)
}

// ── Init ──

onMounted(() => {
  fetchArticles()
})
</script>

<template>
  <div class="articles-page">
    <!-- Header -->
    <div class="page-header">
      <div class="header-left">
        <h1 class="page-title">文章</h1>
        <span class="page-count">{{ total }} 篇</span>
      </div>
      <div class="header-right">
        <div class="filter-tabs">
          <button
            class="filter-tab"
            :class="{ active: statusFilter === '' }"
            @click="statusFilter = ''"
          >
            全部
          </button>
          <button
            class="filter-tab"
            :class="{ active: statusFilter === 'published' }"
            @click="statusFilter = 'published'"
          >
            已发布
          </button>
          <button
            class="filter-tab"
            :class="{ active: statusFilter === 'draft' }"
            @click="statusFilter = 'draft'"
          >
            草稿
          </button>
        </div>
        <div class="search-box">
          <input
            v-model="searchQuery"
            type="text"
            placeholder="搜索文章…"
            class="search-input"
            @input="onSearchInput"
          />
        </div>
        <button
          v-if="loggedIn"
          class="btn-create"
          @click="openCreate"
        >
          新建文章
        </button>
      </div>
    </div>

    <!-- List -->
    <div v-if="loading" class="loading-state">
      <p class="loading-text">加载中…</p>
    </div>

    <div v-else-if="articles.length === 0" class="empty-state">
      <p class="empty-text">暂无文章</p>
      <button
        v-if="loggedIn"
        class="btn-create"
        @click="openCreate"
      >
        写第一篇
      </button>
    </div>

    <div v-else class="article-list">
      <article
        v-for="item in articles"
        :key="item.id"
        class="article-card"
        @click="goDetail(item.id)"
      >
        <div class="card-body">
          <div class="card-meta">
            <span
              class="status-badge"
              :class="item.status"
            >
              {{ item.status === 'published' ? '已发布' : '草稿' }}
            </span>
            <span class="card-date">{{ new Date(item.createdAt).toLocaleDateString('zh-CN') }}</span>
            <span v-if="item.cards.length > 0" class="card-count">
              关联 {{ item.cards.length }} 张卡片
            </span>
          </div>
          <h2 class="card-title">{{ item.title }}</h2>
          <p v-if="item.summary" class="card-summary">{{ item.summary }}</p>
        </div>
        <div v-if="loggedIn" class="card-actions" @click.stop>
          <button class="action-btn" @click="openEdit(item)">编辑</button>
          <button
            class="action-btn danger"
            @click="showConfirm(`确定删除「${item.title}」吗？`, () => handleDelete(item.id))"
          >
            删除
          </button>
        </div>
      </article>
    </div>

    <!-- Pagination -->
    <div v-if="total > pageSize" class="pagination">
      <button
        class="page-btn"
        :disabled="page <= 1"
        @click="onPageChange(-1)"
      >
        上一页
      </button>
      <span class="page-info">{{ page }} / {{ Math.ceil(total / pageSize) }}</span>
      <button
        class="page-btn"
        :disabled="!hasMore"
        @click="onPageChange(1)"
      >
        下一页
      </button>
    </div>

    <!-- Article Form Dialog -->
    <ArticleFormDialog
      :visible="dialogVisible"
      :mode="dialogMode"
      :article="dialogArticle"
      @update:visible="dialogVisible = $event"
      @saved="onArticleSaved"
    />

    <!-- Confirm Dialog -->
    <BoDialog v-model:show="confirmShow">
      <div class="confirm-dialog">
        <p class="confirm-msg">{{ confirmMsg }}</p>
        <div class="confirm-actions">
          <button class="btn-cancel" @click="confirmShow = false">取消</button>
          <button class="btn-save danger" @click="onConfirm">确认删除</button>
        </div>
      </div>
    </BoDialog>
  </div>
</template>

<style scoped>
.articles-page {
  padding: 32px 0 64px;
  flex: 1;
}

/* ── Header ── */

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 32px;
}

.header-left {
  display: flex;
  align-items: baseline;
  gap: 12px;
}

.page-title {
  font-family: var(--font-serif, 'Noto Serif SC', serif);
  font-size: 28px;
  font-weight: 500;
  color: var(--color-ink, #141413);
  margin: 0;
}

.page-count {
  font-size: 14px;
  color: var(--color-muted, #6c6a64);
}

.header-right {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.filter-tabs {
  display: flex;
  gap: 4px;
  background: #efe9de;
  border-radius: 8px;
  padding: 3px;
}

.filter-tab {
  padding: 5px 14px;
  border: none;
  background: none;
  font-size: 13px;
  color: #6c6a64;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s;
}

.filter-tab.active {
  background: #fff;
  color: #141413;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

.search-box {
  position: relative;
}

.search-input {
  padding: 7px 14px;
  border: 1px solid #e6dfd8;
  border-radius: 8px;
  font-size: 13px;
  color: #3d3d3a;
  background: #faf9f5;
  outline: none;
  width: 180px;
  transition: border-color 0.2s;
}

.search-input:focus {
  border-color: #cc785c;
}

.search-input::placeholder {
  color: #b8b2a6;
}

.btn-create {
  padding: 8px 20px;
  background: #cc785c;
  color: #fff;
  border: none;
  border-radius: 8px;
  font-size: 14px;
  cursor: pointer;
  transition: background 0.2s;
}

.btn-create:hover {
  background: #a9583e;
}

/* ── Loading / Empty ── */

.loading-state,
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 80px 0;
  gap: 16px;
}

.loading-text,
.empty-text {
  font-size: 15px;
  color: #6c6a64;
}

/* ── Article List ── */

.article-list {
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: #e6dfd8;
  border-radius: 12px;
  overflow: hidden;
}

.article-card {
  background: #faf9f5;
  padding: 20px 24px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  cursor: pointer;
  transition: background 0.15s;
}

.article-card:hover {
  background: #f5f0e8;
}

.card-body {
  flex: 1;
  min-width: 0;
}

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

.status-badge {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 4px;
  font-weight: 500;
}

.status-badge.published {
  background: #d4edda;
  color: #2d6a4f;
}

.status-badge.draft {
  background: #efe9de;
  color: #8b7e6a;
}

.card-date {
  font-size: 12px;
  color: #b8b2a6;
}

.card-count {
  font-size: 12px;
  color: #8b7e6a;
}

.card-title {
  font-size: 18px;
  font-weight: 500;
  color: #141413;
  margin: 0 0 6px;
  line-height: 1.4;
}

.card-summary {
  font-size: 14px;
  color: #6c6a64;
  margin: 0;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
  padding-top: 4px;
}

.action-btn {
  padding: 4px 12px;
  border: 1px solid #e6dfd8;
  border-radius: 6px;
  background: #fff;
  font-size: 12px;
  color: #6c6a64;
  cursor: pointer;
  transition: all 0.15s;
}

.action-btn:hover {
  border-color: #cc785c;
  color: #cc785c;
}

.action-btn.danger:hover {
  border-color: #c64545;
  color: #c64545;
}

/* ── Pagination ── */

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

.page-btn {
  padding: 6px 16px;
  border: 1px solid #e6dfd8;
  border-radius: 6px;
  background: #faf9f5;
  font-size: 13px;
  color: #3d3d3a;
  cursor: pointer;
  transition: all 0.15s;
}

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

.page-btn:hover:not(:disabled) {
  background: #efe9de;
}

.page-info {
  font-size: 13px;
  color: #6c6a64;
}

/* ── Confirm Dialog (shared button styles) ── */

.btn-cancel {
  padding: 8px 20px;
  border: 1px solid #e6dfd8;
  border-radius: 8px;
  background: #fff;
  font-size: 14px;
  color: #6c6a64;
  cursor: pointer;
}

.btn-cancel:hover {
  background: #f5f0e8;
}

.btn-save {
  padding: 8px 20px;
  border: none;
  border-radius: 8px;
  background: #cc785c;
  font-size: 14px;
  color: #fff;
  cursor: pointer;
  transition: background 0.15s;
}

.btn-save:hover {
  background: #a9583e;
}

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

.btn-save.danger {
  background: #c64545;
}

.btn-save.danger:hover {
  background: #a33;
}

/* ── Confirm Dialog ── */

.confirm-dialog {
  background: #fff;
  border-radius: 12px;
  padding: 24px;
  min-width: 320px;
}

.confirm-msg {
  font-size: 15px;
  color: #3d3d3a;
  margin: 0 0 20px;
}

.confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

/* ── Responsive ── */

@media (max-width: 768px) {
  .articles-page {
    padding: 20px 16px 48px;
  }

  .page-header {
    flex-direction: column;
  }

  .header-right {
    width: 100%;
  }

  .search-input {
    width: 120px;
  }

  .card-actions {
    flex-direction: column;
  }
}
</style>
