<script setup lang="ts">
definePageMeta({
  title: '项目',
})

const { loggedIn, initialized } = useAuthSession()
const { $toast } = useNuxtApp()

// ── State ──
const projects = ref<any[]>([])
const loading = ref(true)
const showForm = ref(false)
const editingProject = ref<any>(null)
const formData = ref({ name: '', tags: '', description: '', path: '' })
const submitting = ref(false)

// ── Intersection-observer entrance ──
const gridEl = ref<HTMLElement | null>(null)

// After cards render, add visible class with stagger
function revealCards() {
  if (!gridEl.value) return
  for (let i = 0; i < gridEl.value.children.length; i++) {
    const child = gridEl.value.children[i] as HTMLElement
    if (child) {
      child.style.setProperty('--idx', String(i))
      child.classList.add('visible')
    }
  }
}

// ── Fetch ──
async function fetchProjects() {
  loading.value = true
  try {
    const res = await $fetch('/api/projects')
    projects.value = (res as any)?.data?.items ?? []
    await nextTick()
    revealCards()
  } catch (e: any) {
    $toast?.error('加载项目失败')
  } finally {
    loading.value = false
  }
}

// ── CRUD ──
function openCreate() {
  editingProject.value = null
  formData.value = { name: '', tags: '', description: '', path: '' }
  showForm.value = true
}

function openEdit(project: any) {
  editingProject.value = project
  formData.value = {
    name: project.name,
    tags: project.tags || '',
    description: project.description || '',
    path: project.path || '',
  }
  showForm.value = true
}

async function submitForm() {
  submitting.value = true
  try {
    const payload = {
      name: formData.value.name,
      tags: formData.value.tags || null,
      description: formData.value.description || null,
      path: formData.value.path || null,
    }
    if (editingProject.value) {
      await $fetch(`/api/projects/${editingProject.value.id}`, { method: 'PUT', body: payload })
      $toast?.success('项目已更新')
    } else {
      await $fetch('/api/projects', { method: 'POST', body: payload })
      $toast?.success('项目已创建')
    }
    showForm.value = false
    await fetchProjects()
  } catch (e: any) {
    $toast?.error(e?.data?.statusMessage || '操作失败')
  } finally {
    submitting.value = false
  }
}

async function deleteProject(project: any) {
  if (!confirm(`确定删除「${project.name}」？`)) return
  try {
    await $fetch(`/api/projects/${project.id}`, { method: 'DELETE' })
    $toast?.success('项目已删除')
    await fetchProjects()
  } catch (e: any) {
    $toast?.error('删除失败')
  }
}

function parseTags(tags: string | null): string[] {
  if (!tags) return []
  return tags.split(',').map(t => t.trim()).filter(Boolean)
}

const cardBgPool = [
  'var(--color-surface-card, #efe9de)',
  'var(--color-surface-soft, #f5f0e8)',
  'var(--color-canvas, #faf9f5)',
]

function cardBg(index: number): string {
  return cardBgPool[index % cardBgPool.length]
}

function padNum(i: number): string {
  return String(i + 1).padStart(2, '0')
}

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

<template>
  <div class="projects-page">
    <!-- Header -->
    <header class="page-header">
      <div class="header-content">
        <p class="page-eyebrow">Portfolio</p>
        <h1 class="page-title">项目</h1>
        <p class="page-subtitle">一些有趣的项目与探索</p>
      </div>
      <button v-if="loggedIn && initialized" class="add-btn" @click="openCreate">
        <span class="add-icon">+</span>
        新建项目
      </button>
    </header>

    <!-- Loading -->
    <div v-if="loading" class="loading-state">
      <span class="loader-dot" />
      <span class="loader-dot" />
      <span class="loader-dot" />
    </div>

    <!-- Empty State -->
    <div v-else-if="projects.length === 0" class="empty-state">
      <div class="empty-mark">✦</div>
      <p class="empty-text">还没有项目</p>
      <p class="empty-hint">项目展示从这里开始</p>
      <button v-if="loggedIn && initialized" class="add-btn" @click="openCreate">
        创建第一个项目
      </button>
    </div>

    <!-- Card Grid -->
    <div v-else ref="gridEl" class="project-grid">
      <article
        v-for="(project, index) in projects"
        :key="project.id"
        :data-index="index"
        class="project-card"
        :class="{ 'card-featured': index === 0 && projects.length < 4 }"
        :style="{ '--card-bg': cardBg(index), '--idx': index }"
      >
        <!-- Decorative index number -->
        <span class="card-index">{{ padNum(index) }}</span>

        <div class="card-body">
          <h3 class="card-title">{{ project.name }}</h3>

          <div v-if="project.tags" class="card-tags">
            <span
              v-for="tag in parseTags(project.tags)"
              :key="tag"
              class="tag-pill"
            >{{ tag }}</span>
          </div>

          <p v-if="project.description" class="card-desc">{{ project.description }}</p>

          <a
            v-if="project.path"
            :href="project.path"
            target="_blank"
            rel="noopener noreferrer"
            class="card-link"
            @click.stop
          >
            <svg class="link-svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
              <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
              <polyline points="15 3 21 3 21 9"/>
              <line x1="10" y1="14" x2="21" y2="3"/>
            </svg>
            <span class="link-label">查看项目</span>
          </a>
        </div>

        <div v-if="loggedIn && initialized" class="card-actions">
          <button class="action-btn" title="编辑" @click="openEdit(project)">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <path d="M17 3a2.85 2.85 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/>
            </svg>
          </button>
          <button class="action-btn action-delete" title="删除" @click="deleteProject(project)">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>
            </svg>
          </button>
        </div>
      </article>
    </div>

    <!-- Form Modal -->
    <Teleport to="body">
      <div v-if="showForm" class="modal-overlay" @click.self="showForm = false">
        <div class="modal-card">
          <div class="modal-header">
            <h2 class="modal-title">{{ editingProject ? '编辑项目' : '新建项目' }}</h2>
            <button class="modal-close" @click="showForm = false">
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M18 6 6 18"/><path d="m6 6 12 12"/>
              </svg>
            </button>
          </div>
          <form class="modal-body" @submit.prevent="submitForm">
            <div class="form-group">
              <label class="form-label">项目名 <span class="required">*</span></label>
              <input v-model="formData.name" class="form-input" placeholder="输入项目名称" required maxlength="100" />
            </div>
            <div class="form-group">
              <label class="form-label">标签</label>
              <input v-model="formData.tags" class="form-input" placeholder="用逗号分隔，如: Vue, Nuxt, 项目" maxlength="500" />
            </div>
            <div class="form-group">
              <label class="form-label">描述</label>
              <textarea v-model="formData.description" class="form-textarea" placeholder="简短的描述" rows="3" maxlength="1000" />
            </div>
            <div class="form-group">
              <label class="form-label">链接</label>
              <input v-model="formData.path" class="form-input" placeholder="https://github.com/..." maxlength="500" />
            </div>
            <div class="modal-footer">
              <button type="button" class="btn-cancel" @click="showForm = false">取消</button>
              <button type="submit" class="btn-submit" :disabled="submitting">
                {{ submitting ? '保存中...' : (editingProject ? '更新' : '创建') }}
              </button>
            </div>
          </form>
        </div>
      </div>
    </Teleport>
  </div>
</template>

<style scoped>
/* ═══════════════════════
   Projects Page — Brand
   ═══════════════════════ */

.projects-page {
  max-width: 1280px;
  margin: 0 auto;
  padding: 32px 32px 80px;
}

/* ─── Header ─── */

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  margin-bottom: 36px;
  gap: 24px;
  flex-wrap: wrap;
}

.header-content {
  flex: 1;
}

.page-eyebrow {
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--color-primary, #cc785c);
  margin: 0 0 8px;
}

.page-title {
  font-family: 'Copernicus', 'Times New Roman', serif;
  font-size: 36px;
  font-weight: 400;
  color: var(--color-ink, #141413);
  letter-spacing: -0.8px;
  margin: 0 0 6px;
  line-height: 1.1;
}

.page-subtitle {
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 16px;
  color: var(--color-muted, #6c6a64);
  margin: 0;
  line-height: 1.55;
}

/* ─── Add Button ─── */

.add-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 14px;
  font-weight: 500;
  color: var(--color-on-primary, #ffffff);
  background: var(--color-primary, #cc785c);
  border: none;
  padding: 11px 22px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.15s ease;
  flex-shrink: 0;
}

.add-btn:hover {
  background: var(--color-primary-active, #a9583e);
}

.add-btn:active {
  transform: scale(0.97);
}

.add-icon {
  font-size: 18px;
  line-height: 1;
}

/* ─── Loading ─── */

.loading-state {
  display: flex;
  justify-content: center;
  gap: 8px;
  padding: 120px 0;
}

.loader-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-primary, #cc785c);
  animation: dotPulse 1.2s ease-in-out infinite;
}

.loader-dot:nth-child(2) { animation-delay: 0.15s; }
.loader-dot:nth-child(3) { animation-delay: 0.3s; }

@keyframes dotPulse {
  0%, 80%, 100% { opacity: 0.2; transform: scale(0.8); }
  40% { opacity: 1; transform: scale(1); }
}

/* ─── Empty State ─── */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 120px 0;
  gap: 12px;
}

.empty-mark {
  font-size: 36px;
  color: var(--color-primary, #cc785c);
  margin-bottom: 8px;
  animation: gentleSpin 4s ease-in-out infinite;
}

@keyframes gentleSpin {
  0%, 100% { transform: rotate(0deg); }
  50% { transform: rotate(180deg); }
}

.empty-text {
  font-family: 'Copernicus', 'Times New Roman', serif;
  font-size: 24px;
  font-weight: 400;
  color: var(--color-ink, #141413);
  margin: 0;
}

.empty-hint {
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 14px;
  color: var(--color-muted, #6c6a64);
  margin: 0 0 8px;
}

/* ═══════════════════════
   Project Grid
   ═══════════════════════ */

.project-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 16px;
}

/* Featured card: first card spans wider when few projects */
.project-grid:has(:only-child) .card-featured,
.project-grid:has(:nth-child(2):last-child) .card-featured {
  grid-column: 1 / -1;
}

/* ─── Card ─── */

.project-card {
  position: relative;
  background: var(--card-bg, var(--color-surface-card, #efe9de));
  border-radius: 14px;
  padding: 24px 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  opacity: 1;
  transform: translateY(32px) rotateX(4deg);
  transition: opacity 0.5s cubic-bezier(0.22, 1, 0.36, 1), transform 0.5s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.35s ease;
  transform-origin: center top;
  will-change: transform, opacity;
}

.project-card.visible {
  opacity: 1;
  transform: translateY(0) rotateX(0deg);
  transition-delay: calc(var(--idx, 0) * 0.08s);
}

.project-card:hover {
  transform: translateY(-4px) scale(1.005);
  box-shadow: 0 12px 36px rgba(20, 20, 19, 0.07);
}

/* ─── Card Index ─── */

.card-index {
  font-family: 'Copernicus', 'Times New Roman', serif;
  font-size: 12px;
  font-weight: 400;
  color: var(--color-primary, #cc785c);
  letter-spacing: 1px;
  line-height: 1;
  opacity: 0.7;
}

/* ─── Card Body ─── */

.card-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.card-title {
  font-family: 'Copernicus', 'Times New Roman', serif;
  font-size: 22px;
  font-weight: 400;
  color: var(--color-ink, #141413);
  margin: 0;
  letter-spacing: -0.3px;
  line-height: 1.25;
}

/* ─── Tags ─── */

.card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

.tag-pill {
  display: inline-block;
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 11px;
  font-weight: 500;
  color: var(--color-primary, #cc785c);
  background: rgba(204, 120, 92, 0.1);
  padding: 3px 9px;
  border-radius: 9999px;
  line-height: 1.4;
  letter-spacing: 0.2px;
}

/* ─── Description ─── */

.card-desc {
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 14px;
  color: var(--color-body, #3d3d3a);
  line-height: 1.6;
  margin: 0;
}

/* ─── Link ─── */

.card-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 13px;
  font-weight: 500;
  color: var(--color-primary, #cc785c);
  text-decoration: none;
  transition: gap 0.2s ease;
  margin-top: 2px;
}

.card-link:hover {
  gap: 10px;
}

.link-svg {
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

.card-link:hover .link-svg {
  transform: translate(2px, -2px);
}

/* ─── Card Actions ─── */

.card-actions {
  display: flex;
  gap: 6px;
  justify-content: flex-end;
  border-top: 1px solid rgba(230, 223, 216, 0.4);
  padding-top: 14px;
}

.action-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
  transition: all 0.2s ease;
  color: var(--color-muted, #6c6a64);
}

.action-btn:hover {
  background: var(--color-canvas, #faf9f5);
  color: var(--color-ink, #141413);
}

.action-delete:hover {
  background: rgba(198, 69, 69, 0.08);
  color: var(--color-error, #c64545);
}

/* ═══════════════════════
   Modal
   ═══════════════════════ */

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(20, 20, 19, 0.45);
  backdrop-filter: blur(5px);
  padding: 24px;
}

.modal-card {
  background: var(--color-canvas, #faf9f5);
  border-radius: 16px;
  width: 100%;
  max-width: 480px;
  box-shadow: 0 20px 60px rgba(20, 20, 19, 0.18);
  animation: modalIn 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

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

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 24px 24px 0;
}

.modal-title {
  font-family: 'Copernicus', 'Times New Roman', serif;
  font-size: 22px;
  font-weight: 400;
  color: var(--color-ink, #141413);
  margin: 0;
  letter-spacing: -0.3px;
}

.modal-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
  color: var(--color-muted, #6c6a64);
  transition: all 0.2s ease;
}

.modal-close:hover {
  background: var(--color-surface-card, #efe9de);
  color: var(--color-ink, #141413);
}

.modal-body {
  padding: 20px 24px 24px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.form-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.form-label {
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 13px;
  font-weight: 500;
  color: var(--color-ink, #141413);
}

.required { color: var(--color-error, #c64545); }

.form-input,
.form-textarea {
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 14px;
  color: var(--color-ink, #141413);
  background: var(--color-canvas, #faf9f5);
  border: 1px solid var(--color-hairline, #e6dfd8);
  border-radius: 8px;
  padding: 10px 14px;
  outline: none;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.form-input:focus,
.form-textarea:focus {
  border-color: var(--color-primary, #cc785c);
  box-shadow: 0 0 0 3px rgba(204, 120, 92, 0.12);
}

.form-textarea {
  resize: vertical;
  min-height: 72px;
}

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding-top: 8px;
}

.btn-cancel {
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 14px;
  font-weight: 500;
  color: var(--color-muted, #6c6a64);
  background: transparent;
  border: 1px solid var(--color-hairline, #e6dfd8);
  padding: 9px 18px;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.2s ease;
}

.btn-cancel:hover {
  background: var(--color-surface-card, #efe9de);
  color: var(--color-ink, #141413);
}

.btn-submit {
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: 14px;
  font-weight: 500;
  color: var(--color-on-primary, #ffffff);
  background: var(--color-primary, #cc785c);
  border: none;
  padding: 9px 22px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.2s ease;
}

.btn-submit:hover { background: var(--color-primary-active, #a9583e); }
.btn-submit:disabled { opacity: 0.6; cursor: not-allowed; }

/* ═══════════════════════
   Responsive
   ═══════════════════════ */

@media (max-width: 768px) {
  .projects-page {
    padding: 40px 20px 80px;
  }

  .page-header {
    flex-direction: column;
    align-items: flex-start;
    margin-bottom: 40px;
  }

  .page-title {
    font-size: 32px;
  }

  .project-grid {
    grid-template-columns: 1fr;
    gap: 16px;
  }

  .project-card {
    padding: 24px 24px 20px;
  }

  .card-title {
    font-size: 20px;
  }
}
</style>
