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

type Feed = {
  id: number
  feedUrl: string
  title: string | null
  lastError: string | null
  lastFetchedAt: string | null
  pollIntervalMinutes: number
  nextSyncAt: string | null
}
type RssSyncMeta = { serverCheckIntervalMinutes: number }
type Item = {
  id: number
  title: string | null
  canonicalUrl: string
  visibility: string
  feedId: number
  shareToken: string | null
}

const feeds = ref<Feed[]>([])
const syncMeta = ref<RssSyncMeta>({ serverCheckIntervalMinutes: 60 })
const items = ref<Item[]>([])
const feedUrl = ref('')
const loading = ref(true)
const selectedFeedId = ref<number | null>(null)
const copiedItemId = ref<number | null>(null)
let copyResetTimer: ReturnType<typeof setTimeout> | undefined

const { user, refresh } = useAuthSession()
const { fetchData } = useClientApi()
const toast = useToast()

const filteredItems = computed(() => {
  if (selectedFeedId.value === null) {
    return items.value
  }
  return items.value.filter((it) => it.feedId === selectedFeedId.value)
})

const selectedFeedLabel = computed(() => {
  if (selectedFeedId.value === null) {
    return '全部订阅'
  }
  const f = feeds.value.find((x) => x.id === selectedFeedId.value)
  return f?.title || f?.feedUrl || '当前订阅'
})

function formatNextSync(iso: string) {
  return new Date(iso).toLocaleString('zh-CN', { dateStyle: 'short', timeStyle: 'short' })
}

const earliestNextSyncLabel = computed(() => {
  const dates = feeds.value.map((f) => f.nextSyncAt).filter(Boolean) as string[]
  if (!dates.length) {
    return null
  }
  return formatNextSync(dates.reduce((a, b) => (a < b ? a : b)))
})

function feedNextLine(f: Feed) {
  if (!f.nextSyncAt) {
    return '尚未完成首次抓取，后台将自动重试'
  }
  return `预计下次同步：${formatNextSync(f.nextSyncAt)}`
}

function countForFeed(feedId: number) {
  return items.value.filter((it) => it.feedId === feedId).length
}

function unlistedSharePath(publicSlug: string, token: string) {
  return `/p/${encodeURIComponent(publicSlug)}/t/${encodeURIComponent(token)}`
}

function unlistedShareFullUrl(publicSlug: string, token: string) {
  if (import.meta.client) {
    return `${window.location.origin}${unlistedSharePath(publicSlug, token)}`
  }
  return unlistedSharePath(publicSlug, token)
}

async function load() {
  loading.value = true
  try {
    const [f, i] = await Promise.all([
      fetchData<{ feeds: Feed[]; sync: RssSyncMeta }>('/api/me/rss/feeds'),
      fetchData<{ items: Item[] }>('/api/me/rss/items'),
    ])
    syncMeta.value = f.sync
    feeds.value = f.feeds
    items.value = i.items
    if (selectedFeedId.value !== null && !feeds.value.some((x) => x.id === selectedFeedId.value)) {
      selectedFeedId.value = null
    }
  } finally {
    loading.value = false
  }
}

onMounted(async () => {
  await Promise.all([refresh(), load()])
})

async function addFeed() {
  await fetchData('/api/me/rss/feeds', { method: 'POST', body: { feedUrl: feedUrl.value } })
  feedUrl.value = ''
  await load()
  toast.add({ title: '已添加订阅', color: 'success' })
}

async function syncAll() {
  await fetchData('/api/me/rss/sync', { method: 'POST', body: {} })
  await load()
  toast.add({ title: '同步完成', color: 'success' })
}

async function removeFeed(id: number) {
  await fetchData(`/api/me/rss/feeds/${id}`, { method: 'DELETE' })
  if (selectedFeedId.value === id) {
    selectedFeedId.value = null
  }
  await load()
  toast.add({ title: '已删除订阅', color: 'success' })
}

async function setItemVis(id: number, visibility: string) {
  await fetchData(`/api/me/rss/items/${id}`, { method: 'PATCH', body: { visibility } })
  await load()
  toast.add({ title: '可见性已更新', color: 'success' })
}

async function copyUnlistedLink(it: Item) {
  const slug = user.value?.publicSlug?.trim()
  if (!slug || !it.shareToken) {
    return
  }
  const text = unlistedShareFullUrl(slug, it.shareToken)
  try {
    await navigator.clipboard.writeText(text)
    copiedItemId.value = it.id
    if (copyResetTimer) {
      clearTimeout(copyResetTimer)
    }
    copyResetTimer = setTimeout(() => {
      copiedItemId.value = null
    }, 2000)
  } catch {
    // ignore
  }
}
</script>

<template>
  <UContainer class="py-8 space-y-8 max-w-4xl">
    <h1 class="text-2xl font-semibold">
      RSS 收件箱
    </h1>
    <p v-if="!loading" class="text-sm text-muted -mt-4">
      服务器约每 {{ syncMeta.serverCheckIntervalMinutes }} 分钟检查一次到期的订阅；添加新订阅后会立即抓取一次。
      <template v-if="feeds.length && earliestNextSyncLabel">
        当前全部订阅中，预计最早下次同步时间为 {{ earliestNextSyncLabel }}（按各源上次抓取时间推算，仅供参考）。
      </template>
    </p>

    <UCard>
      <div class="flex flex-col sm:flex-row gap-2">
        <UInput v-model="feedUrl" placeholder="https://example.com/feed.xml" class="flex-1" />
        <UButton @click="addFeed">
          添加订阅
        </UButton>
        <UButton color="neutral" variant="outline" @click="syncAll">
          全部同步
        </UButton>
      </div>
    </UCard>

    <div v-if="loading" class="text-muted">
      加载中…
    </div>
    <div v-else class="grid md:grid-cols-3 gap-6">
      <UCard class="md:col-span-1">
        <template #header>
          订阅源（仅自己可见）
        </template>
        <UEmpty v-if="!feeds.length" title="暂无订阅" />
        <ul v-else class="space-y-2 text-sm">
          <li>
            <button
              type="button"
              class="w-full text-left rounded-lg border px-3 py-2 transition-colors"
              :class="selectedFeedId === null
                ? 'border-primary bg-primary/10 ring-2 ring-primary/30'
                : 'border-default hover:bg-elevated/60'"
              @click="selectedFeedId = null"
            >
              <div class="font-medium">
                全部订阅
              </div>
              <div class="text-xs text-muted mt-0.5">
                {{ items.length }} 条
              </div>
            </button>
          </li>
          <li v-for="f in feeds" :key="f.id">
            <div
              class="rounded-lg border transition-colors"
              :class="selectedFeedId === f.id
                ? 'border-primary bg-primary/10 ring-2 ring-primary/30'
                : 'border-default hover:bg-elevated/60'"
            >
              <button
                type="button"
                class="w-full text-left px-3 pt-2 pb-1"
                @click="selectedFeedId = f.id"
              >
                <div class="font-medium truncate pr-1" :title="f.feedUrl">
                  {{ f.title || f.feedUrl }}
                </div>
                <div class="text-xs text-muted mt-0.5">
                  {{ countForFeed(f.id) }} 条
                </div>
                <div class="text-[11px] text-muted mt-1 leading-snug">
                  {{ feedNextLine(f) }}
                </div>
              </button>
              <div v-if="f.lastError" class="px-3 text-error text-xs">
                {{ f.lastError }}
              </div>
              <div class="px-3 pb-2">
                <UButton size="xs" color="error" variant="ghost" class="-ml-2" @click.stop="removeFeed(f.id)">
                  删除订阅
                </UButton>
              </div>
            </div>
          </li>
        </ul>
      </UCard>
      <UCard class="md:col-span-2">
        <template #header>
          条目
        </template>
        <p class="text-xs text-muted mb-2 -mt-1">
          同步入库的新条目默认为「私密」。只有设为「公开」的条目会出现在你的公开主页「阅读」区块。
        </p>
        <p class="text-xs font-medium text-highlighted mb-3">
          当前：{{ selectedFeedLabel }}（{{ filteredItems.length }} 条）
        </p>
        <UEmpty v-if="!items.length" title="暂无条目" description="添加订阅并点击同步" />
        <UEmpty
          v-else-if="!filteredItems.length"
          title="该订阅下暂无条目"
          description="切换左侧订阅或先执行同步"
        />
        <ul v-else class="space-y-3 text-sm">
          <li v-for="it in filteredItems" :key="it.id" class="border border-default rounded-lg p-3">
            <a
              :href="it.canonicalUrl"
              target="_blank"
              rel="noopener noreferrer"
              class="text-primary font-medium hover:underline"
            >{{ it.title || '未命名' }}</a>
            <div class="mt-2 text-xs text-muted">
              谁能看到
            </div>
            <div class="mt-1 flex flex-wrap gap-1.5">
              <UButton
                size="xs"
                :color="it.visibility === 'private' ? 'primary' : 'neutral'"
                :variant="it.visibility === 'private' ? 'solid' : 'outline'"
                @click="setItemVis(it.id, 'private')"
              >
                私密
              </UButton>
              <UButton
                size="xs"
                :color="it.visibility === 'public' ? 'primary' : 'neutral'"
                :variant="it.visibility === 'public' ? 'solid' : 'outline'"
                @click="setItemVis(it.id, 'public')"
              >
                公开
              </UButton>
              <UButton
                size="xs"
                :color="it.visibility === 'unlisted' ? 'primary' : 'neutral'"
                :variant="it.visibility === 'unlisted' ? 'solid' : 'outline'"
                @click="setItemVis(it.id, 'unlisted')"
              >
                仅链接
              </UButton>
            </div>
            <div
              v-if="it.visibility === 'unlisted'"
              class="mt-3 rounded-md border border-default bg-elevated/40 px-3 py-2 space-y-2"
            >
              <p class="text-xs text-muted leading-relaxed">
                「仅链接」不会出现在公开主页；把下面地址发给他人即可打开本条目的摘要页（无需登录）。
              </p>
              <template v-if="user?.publicSlug?.trim() && it.shareToken">
                <div class="flex flex-col sm:flex-row gap-2">
                  <UInput
                    readonly
                    size="sm"
                    class="font-mono text-xs flex-1 min-w-0"
                    :model-value="unlistedShareFullUrl(user.publicSlug.trim(), it.shareToken)"
                  />
                  <div class="flex shrink-0 gap-1.5">
                    <UButton size="sm" @click="copyUnlistedLink(it)">
                      {{ copiedItemId === it.id ? '已复制' : '复制链接' }}
                    </UButton>
                    <UButton
                      size="sm"
                      color="neutral"
                      variant="outline"
                      :to="unlistedSharePath(user.publicSlug.trim(), it.shareToken)"
                      target="_blank"
                    >
                      打开
                    </UButton>
                  </div>
                </div>
              </template>
              <UAlert
                v-else
                color="warning"
                variant="subtle"
                title="无法生成分享地址"
                description="请先在「个人资料」中设置公开主页标识（/@slug），保存后再将本条设为「仅链接」。"
              />
            </div>
          </li>
        </ul>
      </UCard>
    </div>
  </UContainer>
</template>
