<template>
  <div class="page-wrap">
    <div class="container">
      <!-- 顶部：左右对称 -->
      <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
        <!-- 左：标题说明 -->
        <div class="panel h-full">
          <h1 class="text-2xl font-semibold text-slate-900">
            {{ isEditing ? '编辑资讯文章' : '发布资讯文章' }}
          </h1>
          <p class="text-sm text-slate-500 mt-2">
            支持粘贴图片、丰富排版、表格与高亮。可直接粘贴截图或拖拽图片到编辑区。
          </p>
        </div>

        <!-- 右：当前用户 -->
        <div class="panel h-full">
          <div class="flex items-start justify-between">
            <div>
              <div class="text-sm text-slate-500">当前用户</div>
              <div v-if="me" class="mt-1.5">
                <div class="text-slate-900 font-medium leading-6 truncate">
                  昵称：{{ me.username }}
                </div>
                <div class="text-slate-500 text-sm leading-5 truncate">
                  邮箱：{{ me.email }}
                </div>
              </div>
              <div v-else class="mt-1.5 text-slate-400 text-sm">读取中…</div>
            </div>
            <span
              v-if="me"
              class="inline-flex items-center gap-2 text-xs text-emerald-600"
            >
              <span class="w-2 h-2 rounded-full bg-emerald-500"></span>
              已登录
            </span>
          </div>

          <div class="mt-4 grid grid-cols-2 gap-3 text-xs text-slate-500">
            <div>自动保存：开启</div>
            <div v-if="autoSavedAt" class="text-right">
              最近：{{ fromNow(autoSavedAt) }}
            </div>
          </div>
        </div>
      </div>

      <!-- 提示条 -->
      <transition name="fade">
        <div
          v-if="tip"
          class="rounded-md p-3 text-sm border mb-4"
          :class="
            tip.type === 'error'
              ? 'bg-rose-50 border-rose-200 text-rose-700'
              : 'bg-emerald-50 border-emerald-200 text-emerald-700'
          "
        >
          {{ tip.message }}
        </div>
      </transition>

      <!-- 表单卡片 -->
      <div class="panel shadow-card">
        <div class="grid gap-6">
          <!-- 标题 -->
          <div>
            <label class="label">
              标题 <span class="text-rose-500">*</span>
            </label>
            <div class="relative">
              <input
                v-model.trim="form.title"
                type="text"
                required
                class="ui-input"
                placeholder="例如：AI 在营销自动化中的 5 个落地案例"
                maxlength="120"
              />
              <span class="counter">{{ form.title?.length || 0 }}/120</span>
            </div>
          </div>

          <!-- 摘要 -->
          <div>
            <div class="flex items-baseline justify-between">
              <label class="label">
                摘要 <span class="text-slate-400 text-xs">(选填)</span>
              </label>
              <span class="text-xs text-slate-400">
                {{ form.description?.length || 0 }}/200
              </span>
            </div>
            <textarea
              v-model.trim="form.description"
              rows="3"
              maxlength="200"
              class="ui-textarea"
              placeholder="一句话或一小段话，概括文章要点…"
            />
          </div>

          <!-- 封面图片（选填） -->
          <div>
            <label class="label">
              封面图片 <span class="text-slate-400 text-xs">(选填)</span>
            </label>

            <div class="cover-upload">
              <!-- 预览：本地 blob 优先，其次使用已保存 URL -->
              <div v-if="form.coverPreview || form.cover" class="cover-preview">
                <img
                  :src="form.coverPreview || form.cover"
                  alt="封面预览"
                  class="cover-img"
                />
              </div>

              <!-- 选择封面（仅本地预览，不立刻上传） -->
              <label class="btn btn-outline btn-xs">
                选择封面
                <input
                  class="cover-input"
                  type="file"
                  accept="image/*"
                  @change="onPickCover"
                />
              </label>

              <!-- 移除封面 -->
              <button
                v-if="form.coverPreview || form.cover"
                type="button"
                class="btn btn-ghost btn-xs"
                @click="removeCover"
              >
                移除
              </button>
            </div>

            <p class="mt-1 text-[10px] text-slate-400">
              建议尺寸 800x400 或相似比例，体积 &lt; 500KB。
              封面文件仅在文章发布成功时上传保存。
            </p>
          </div>

          <!-- 正文 -->
          <div>
            <div class="flex items-center justify-between mb-2">
              <label class="label">
                正文 <span class="text-rose-500">*</span>
              </label>
              <div class="text-xs text-slate-400">字数：{{ wordCount }}</div>
            </div>

            <RichEditor v-model="form.body" />

            <p class="mt-2 text-xs text-slate-500">
              小技巧：截屏后直接
              <kbd class="kbd">Ctrl</kbd>+<kbd class="kbd">V</kbd>
              即可插入图片（正文内图片会即时上传）。
            </p>
          </div>

          <!-- 标签 -->
          <div>
            <label class="label mb-1">标签</label>
            <div class="flex gap-2">
              <input
                v-model.trim="tagInput"
                @keydown.enter.prevent="addTag()"
                @keydown.,.prevent="addTag()"
                class="ui-input flex-1"
                placeholder="例如：AI, 营销, OpenAI"
              />
              <button type="button" class="btn btn-outline" @click="addTag()">
                添加
              </button>
            </div>

            <div v-if="form.tagList.length" class="mt-3 flex flex-wrap gap-2">
              <span v-for="(t, i) in form.tagList" :key="t + i" class="chip">
                {{ t }}
                <button type="button" class="chip-close" @click="removeTag(i)">
                  ✕
                </button>
              </span>
            </div>
          </div>
        </div>

        <!-- 操作区 -->
        <div class="actions">
          <span v-if="autoSavedAt" class="text-xs text-emerald-600 mr-auto">
            已自动保存 {{ fromNow(autoSavedAt) }}
          </span>

          <button
            type="button"
            class="btn btn-ghost"
            @click="saveDraftManually"
          >
            手动保存草稿
          </button>
          <button type="button" class="btn btn-ghost" @click="clearDraft">
            清空草稿
          </button>

          <button
            type="button"
            class="btn btn-primary"
            :disabled="submitting"
            @click="submit"
          >
            <svg v-if="submitting" class="spinner" viewBox="0 0 50 50">
              <circle
                class="path"
                cx="25"
                cy="25"
                r="20"
                fill="none"
                stroke-width="5"
              />
            </svg>
            <span>
              {{
                submitting
                  ? (isEditing ? '保存中…' : '发布中…')
                  : (isEditing ? '保存修改' : '发布文章')
              }}
            </span>
          </button>
        </div>
      </div>

      <!-- 额外说明 -->
      <p class="text-xs text-slate-500 mt-3">
        发布须知：请确保不含敏感信息；正文图片为即时上传，封面图片在发布时统一写入后端。
      </p>
    </div>
  </div>
</template>

<script setup>
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { useRoute, onBeforeRouteUpdate } from 'vue-router'
import { navigateTo } from '#app'
import RichEditor from '@/components/RichEditor.vue'
import { useAuthToken, useApi } from '@/composables/useApi'
import { useUpload } from '@/composables/useUpload'
import { useImageExtractor } from '@/composables/useImageExtractor'

const route = useRoute()
const { token } = useAuthToken()
const api = useApi()
const { uploadImage } = useUpload()
const { extractFirstImage } = useImageExtractor()
const editSlug = computed(() =>
  typeof route.query.slug === 'string' ? route.query.slug : null,
)
const isEditing = computed(() => Boolean(editSlug.value))

// 当前用户
const me = ref(null)
async function fetchMe() {
  if (!token.value) return
  try {
    const resp = await api.get('/user')
    me.value = resp?.user ?? null
  } catch {
    me.value = null
  }
}

// 表单
const form = reactive({
  title: '',
  description: '',
  body: '',
  tagList: [],
  cover: '',         // 最终写入后端的 URL
  coverPreview: '',  // 本地预览 blob
})
const coverFile = ref(null)

const tagInput = ref('')
const submitting = ref(false)
const tip = ref(null)
const previewHtml = computed(() => form.body || '')

function resetForm() {
  form.title = ''
  form.description = ''
  form.body = ''
  form.tagList = []
  form.cover = ''
  if (form.coverPreview && form.coverPreview.startsWith('blob:')) {
    URL.revokeObjectURL(form.coverPreview)
  }
  form.coverPreview = ''
  coverFile.value = null
}

async function loadArticleForEdit(slug) {
  try {
    const res = await api.get(`/articles/${slug}`)
    const data = res?.article
    if (!data) return
    form.title = data.title || ''
    form.description = data.description || ''
    form.body = data.body || ''
    const tags = Array.isArray(data.tagList) ? data.tagList : data.tags
    form.tagList = Array.isArray(tags) ? [...tags] : []
    form.cover = data.cover || ''
    form.coverPreview = ''
    coverFile.value = null
    autoSavedAt.value = Date.now()
  } catch (error) {
    console.error('[edit-article] load article failed:', error)
    tip.value = { type: 'error', message: '加载文章详情失败' }
  }
}

// 生命周期
function applyDraftData(draft = {}) {
  form.title = draft.title || ''
  form.description = draft.description || ''
  form.body = draft.body || ''
  form.tagList = Array.isArray(draft.tagList) ? [...draft.tagList] : []
  form.cover = draft.cover || ''
  if (form.coverPreview && form.coverPreview.startsWith('blob:')) {
    URL.revokeObjectURL(form.coverPreview)
  }
  form.coverPreview = ''
  coverFile.value = null
  autoSavedAt.value = Date.now()
}

function readDraft() {
  if (!process.client) return { loaded: false, hasContent: false, data: null }
  const raw = localStorage.getItem(draftKey.value)
  if (!raw) return { loaded: false, hasContent: false, data: null }
  try {
    const data = JSON.parse(raw) || {}
    const hasContent = Boolean(
      data.title ||
        data.description ||
        data.body ||
        (Array.isArray(data.tagList) && data.tagList.length) ||
        data.cover,
    )
    return { loaded: true, hasContent, data }
  } catch {
    return { loaded: false, hasContent: false, data: null }
  }
}

async function initEditor(slug) {
  resetForm()
  if (slug) {
    await loadArticleForEdit(slug)
  } else {
    const draftInfo = readDraft()
    if (draftInfo.hasContent && draftInfo.data) {
      applyDraftData(draftInfo.data)
    }
  }
}

onMounted(async () => {
  if (!token.value) {
    navigateTo('/login')
    return
  }
  await fetchMe()
  await initEditor(editSlug.value)
})

onBeforeRouteUpdate(async (to, from, next) => {
  const slug =
    typeof to.query.slug === 'string'
      ? to.query.slug
      : null
  await initEditor(slug)
  next()
})

// 正文字数
const wordCount = computed(
  () => form.body.replace(/<[^>]+>/g, '').trim().length,
)

// 标签
function addTag() {
  if (!tagInput.value) return
  tagInput.value
    .split(/[，,]/)
    .map(s => s.trim())
    .filter(Boolean)
    .forEach((t) => {
      if (!form.tagList.includes(t)) form.tagList.push(t)
    })
  tagInput.value = ''
}
function removeTag(i) {
  form.tagList.splice(i, 1)
}

// 选择封面：仅更新本地预览 & 待上传文件
function onPickCover(e) {
  const file = e.target.files?.[0]
  e.target.value = ''
  if (!file) return

  if (form.coverPreview && form.coverPreview.startsWith('blob:')) {
    URL.revokeObjectURL(form.coverPreview)
  }

  coverFile.value = file
  form.coverPreview = URL.createObjectURL(file)
}

// 移除封面
function removeCover() {
  if (form.coverPreview && form.coverPreview.startsWith('blob:')) {
    URL.revokeObjectURL(form.coverPreview)
  }
  coverFile.value = null
  form.coverPreview = ''
  form.cover = ''
}

// 草稿
const draftKey = computed(() =>
  editSlug.value ? `article:edit:${editSlug.value}` : 'article:new:draft:v2',
)
const autoSavedAt = ref(0)

function loadDraft() {
  const info = readDraft()
  if (!editSlug.value && info.hasContent && info.data) {
    applyDraftData(info.data)
    return { loaded: true, hasContent: true }
  }
  return info
}

function saveDraft() {
  if (!process.client) return
  const payload = {
    title: form.title,
    description: form.description,
    body: form.body,
    tagList: form.tagList,
    cover: form.cover,
  }
  localStorage.setItem(draftKey.value, JSON.stringify(payload))
  autoSavedAt.value = Date.now()
}

function saveDraftManually() {
  saveDraft()
  tip.value = { type: 'success', message: '草稿已保存到本地' }
  setTimeout(() => { tip.value = null }, 1500)
}

function clearDraft() {
  if (process.client) localStorage.removeItem(draftKey.value)
  if (form.coverPreview && form.coverPreview.startsWith('blob:')) {
    URL.revokeObjectURL(form.coverPreview)
  }
  form.title = ''
  form.description = ''
  form.body = ''
  form.tagList = []
  form.cover = ''
  form.coverPreview = ''
  coverFile.value = null
  tip.value = { type: 'success', message: '草稿已清空' }
  setTimeout(() => { tip.value = null }, 1500)
}

let t = null
watch(
  () => ({
    title: form.title,
    description: form.description,
    body: form.body,
    tagList: form.tagList,
    cover: form.cover,
  }),
  () => {
    clearTimeout(t)
    t = setTimeout(saveDraft, 500)
  },
  { deep: true },
)

function fromNow(ts) {
  const s = Math.max(1, Math.round((Date.now() - ts) / 1000))
  if (s < 60) return `${s}s 前`
  const m = Math.round(s / 60)
  if (m < 60) return `${m} 分钟前`
  return `${Math.round(m / 60)} 小时前`
}

// 提交
async function submit() {
  if (!form.title?.trim() || !form.body?.trim()) {
    tip.value = { type: 'error', message: '标题与正文为必填项' }
    return
  }
  if (!token.value) {
    tip.value = { type: 'error', message: '请先登录' }
    navigateTo('/login')
    return
  }

  submitting.value = true
  tip.value = null

  try {
    // 1. 有新封面则先上传
    let coverUrl = form.cover || ''
    if (coverFile.value) {
      const url = await uploadImage(coverFile.value)
      coverUrl = url
      form.cover = url            // ✅ 回写，确保 payload / 草稿里都有
    }

    // 2. 如果没有封面，尝试从正文中提取第一张图片
    if (!coverUrl && form.body) {
      const firstImage = extractFirstImage(form.body)
      if (firstImage) {
        coverUrl = firstImage
        console.log('📸 自动提取封面图片:', firstImage)
      }
    }

    // 3. 创建文章
    const payload = {
      article: {
        title: form.title.trim(),
        description: form.description?.trim() || '',
        body: form.body,
        tagList: form.tagList,
        cover: coverUrl || null,
      },
    }

    let res
    if (isEditing.value && editSlug.value) {
      res = await api.put(`/articles/${editSlug.value}`, payload)
    } else {
      res = await api.post('/articles', payload)
    }

    clearDraft()
    tip.value = {
      type: 'success',
      message: isEditing.value ? '修改已保存！' : '发布成功！',
    }

    const slug = res?.article?.slug || editSlug.value
    setTimeout(() => {
      navigateTo(slug ? `/articles/${slug}` : '/')
    }, 600)
  } catch (e) {
    console.error('[new-article] submit error:', e)
    tip.value = {
      type: 'error',
      message:
        e?.statusMessage ||
        e?.data?.detail ||
        e?.data?.errors?.[0] ||
        '发布失败，请稍后重试',
    }
  } finally {
    submitting.value = false
  }
}
</script>

<style scoped>
/* 样式保持你的原版，这里不改动 */
.page-wrap {
  margin: 100px 5%;
}
.container {
  max-width: 1200px;
  margin-left: auto;
  margin-right: auto;
  padding: 0 20px;
}
.panel {
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 16px;
  padding: 16px 18px;
  min-height: 120px;
}
.shadow-card {
  box-shadow: 0 8px 28px rgba(10, 18, 33, 0.12);
  overflow: hidden;
}
.actions {
  position: sticky;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding-top: 12px;
  margin-top: 8px;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0) 0%,
    #fff 24px
  );
}
.label {
  display: block;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 500;
  color: #334155;
  margin-bottom: 0.25rem;
}
.ui-input,
.ui-textarea {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  border-radius: 14px;
  border: 1px solid #e5e7eb;
  padding: 10px 14px;
  outline: none;
  background: #fff;
  transition: box-shadow 0.15s ease, border-color 0.15s ease,
    transform 0.02s ease;
  box-shadow: 0 1px 0 rgba(2, 6, 23, 0.02) inset;
}
.ui-input::placeholder,
.ui-textarea::placeholder {
  color: #9aa3b2;
}
.ui-input:hover,
.ui-textarea:hover {
  border-color: #d2d6dc;
}
.ui-input:focus,
.ui-textarea:focus {
  border-color: #6366f1;
  box-shadow: inset 0 0 0 1px #6366f1;
}
.ui-textarea {
  min-height: 110px;
  resize: vertical;
}
.counter {
  position: absolute;
  right: 10px;
  bottom: 8px;
  font-size: 11px;
  color: #98a2b3;
}
.cover-upload {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.cover-input {
  display: none;
}
.cover-preview {
  width: 110px;
  height: 66px;
  border-radius: 10px;
  border: 1px solid #e5e7eb;
  background: #f8fafc;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.cover-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.btn-xs {
  height: 30px;
  padding: 0 10px;
  font-size: 12px;
}
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border-radius: 12px;
  line-height: 1;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.02s ease, box-shadow 0.15s ease,
    background 0.15s ease, border-color 0.15s ease;
}
.btn {
  height: 40px;
  padding: 0 14px;
  font-size: 14px;
}
.btn:active {
  transform: translateY(0.5px);
}
.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.btn-primary {
  color: #fff;
  background: linear-gradient(135deg, #4f46e5, #2563eb);
  box-shadow: 0 6px 18px rgba(37, 99, 235, 0.25);
}
.btn-primary:hover {
  filter: brightness(1.03);
  box-shadow: 0 8px 22px rgba(37, 99, 235, 0.28);
}
.btn-outline {
  background: #fff;
  border-color: #e5e7eb;
  color: #334155;
}
.btn-outline:hover {
  border-color: #cbd5e1;
  box-shadow: 0 6px 16px rgba(2, 6, 23, 0.06);
}
.btn-ghost {
  background: #fff;
  border-color: #e5e7eb;
  color: #475569;
}
.btn-ghost:hover {
  background: #f8fafc;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  padding: 6px 8px 6px 12px;
  background: #f1f5f9;
  color: #334155;
  border: 1px solid #e2e8f0;
  border-radius: 999px;
}
.chip-close {
  color: #64748b;
}
.chip-close:hover {
  color: #ef4444;
}
.kbd {
  padding: 0 0.4rem;
  border: 1px solid #cbd5e1;
  border-radius: 6px;
  background: #f8fafc;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.spinner {
  width: 18px;
  height: 18px;
}
.spinner .path {
  stroke: #fff;
  stroke-linecap: round;
  animation: dash 1.2s ease-in-out infinite;
}
@keyframes dash {
  0% {
    stroke-dasharray: 1, 150;
    stroke-dashoffset: 0;
  }
  50% {
    stroke-dasharray: 90, 150;
    stroke-dashoffset: -35;
  }
  100% {
    stroke-dasharray: 90, 150;
    stroke-dashoffset: -124;
  }
}
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.18s ease;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>
