<script setup lang="ts">
import { unwrapApiBody, type ApiResponse } from '../../utils/http/factory'
import { safeExternalHref } from '../../utils/safe-external-href'

type Section = 'posts' | 'timeline' | 'reading'

type SocialLink = {
  label: string
  icon?: string
  safeHref: string
}

type PostItem = {
  title?: string | null
  excerpt?: string | null
  slug?: string | null
  publishedAt?: Date | string | null
}

type TimelineItem = {
  id?: number
  title?: string | null
  occurredOn?: Date | string | null
  bodyMarkdown?: string | null
  linkUrl?: string | null
}

type ReadingItem = {
  title?: string | null
  canonicalUrl?: string | null
  canonical_url?: string | null
}

type ListPayload<T> = {
  items: T[]
  total: number
  page: number
  pageSize: number
}

const props = defineProps<{
  slug: string
  displayName: string
  publicSlug: string | null
  avatar: string | null
  bioPreviewText: string
  hasBioPreview: boolean
  socialLinks: SocialLink[]
}>()

const activeSection = ref<Section>('posts')
const postsPage = ref(1)
const timelinePage = ref(1)
const readingPage = ref(1)

const { data: postsData, pending: postsPending } = await useAsyncData(
  () => `reader-posts-${props.slug}-${postsPage.value}`,
  async () => {
    const base = `/api/public/profile/${encodeURIComponent(props.slug)}/posts`
    const url = postsPage.value > 1 ? `${base}?page=${postsPage.value}` : base
    const res = await $fetch<ApiResponse<ListPayload<PostItem>>>(url)
    return unwrapApiBody(res)
  },
  { watch: [() => props.slug, postsPage] },
)

const { data: timelineData, pending: timelinePending } = await useAsyncData(
  () => `reader-timeline-${props.slug}-${timelinePage.value}`,
  async () => {
    const base = `/api/public/profile/${encodeURIComponent(props.slug)}/timeline`
    const url = timelinePage.value > 1 ? `${base}?page=${timelinePage.value}` : base
    const res = await $fetch<ApiResponse<ListPayload<TimelineItem>>>(url)
    return unwrapApiBody(res)
  },
  { watch: [() => props.slug, timelinePage] },
)

const { data: readingData, pending: readingPending } = await useAsyncData(
  () => `reader-reading-${props.slug}-${readingPage.value}`,
  async () => {
    const base = `/api/public/profile/${encodeURIComponent(props.slug)}/reading`
    const url = readingPage.value > 1 ? `${base}?page=${readingPage.value}` : base
    const res = await $fetch<ApiResponse<ListPayload<ReadingItem>>>(url)
    return unwrapApiBody(res)
  },
  { watch: [() => props.slug, readingPage] },
)

const postsTotal = computed(() => postsData.value?.total ?? 0)
const timelineTotal = computed(() => timelineData.value?.total ?? 0)
const readingTotal = computed(() => readingData.value?.total ?? 0)

watch(() => props.slug, () => {
  postsPage.value = 1
  timelinePage.value = 1
  readingPage.value = 1
  activeSection.value = 'posts'
})

function postTitle(it: PostItem): string {
  const t = it.title
  return typeof t === 'string' && t.trim().length ? t : '未命名文章'
}

function postExcerpt(it: PostItem): string {
  return typeof it.excerpt === 'string' ? it.excerpt : ''
}

function postSlug(it: PostItem): string {
  return typeof it.slug === 'string' ? it.slug : ''
}

function timelineTitle(it: TimelineItem): string {
  const t = it.title
  return typeof t === 'string' && t.trim().length ? t : '未命名动态'
}

function timelineBody(it: TimelineItem): string {
  return typeof it.bodyMarkdown === 'string' ? it.bodyMarkdown : ''
}

function timelineKey(it: TimelineItem, index: number): string | number {
  return it.id ?? index
}

function timelineHref(it: TimelineItem): string | undefined {
  return safeExternalHref(it.linkUrl)
}

function readingTitle(it: ReadingItem): string {
  const t = it.title
  return typeof t === 'string' && t.trim().length ? t : '未命名'
}

function readingHref(it: ReadingItem): string | undefined {
  return safeExternalHref(it.canonicalUrl ?? it.canonical_url)
}

function readingHost(href: string | undefined): string {
  if (!href) {
    return ''
  }
  try {
    return new URL(href).hostname
  }
  catch {
    return href
  }
}
</script>

<template>
  <div class="grid gap-6 lg:grid-cols-[16rem_minmax(0,1fr)] xl:gap-8">
    <aside class="space-y-4 lg:sticky lg:top-20 lg:h-fit">
      <section class="rounded-2xl border border-default/80 bg-elevated/20 px-4 py-5">
        <div class="flex items-center gap-3">
          <img
            v-if="avatar"
            :src="avatar"
            alt=""
            class="h-14 w-14 rounded-full border border-default object-cover"
          >
          <div>
            <p class="font-semibold text-highlighted">
              {{ displayName }}
            </p>
            <p v-if="publicSlug" class="text-xs text-muted">
              @{{ publicSlug }}
            </p>
          </div>
        </div>
        <NuxtLink
          v-if="hasBioPreview"
          :to="`/@${slug}/about`"
          class="mt-3 block rounded-lg border border-default/70 bg-default/20 px-3 py-2 text-xs text-muted hover:bg-elevated/40"
        >
          {{ bioPreviewText }}
        </NuxtLink>
        <ul v-if="socialLinks.length" class="mt-3 flex flex-wrap gap-2">
          <li v-for="(l, i) in socialLinks" :key="i">
            <a
              :href="l.safeHref"
              target="_blank"
              rel="noopener noreferrer"
              class="inline-flex items-center gap-1 rounded-md border border-default px-2 py-1 text-xs text-muted hover:text-default"
            >
              <UIcon :name="socialLinkIconName({ ...l, url: l.safeHref })" class="size-3.5" />
              {{ l.label }}
            </a>
          </li>
        </ul>
      </section>

      <nav class="space-y-1 rounded-2xl border border-default/80 bg-elevated/20 p-2" aria-label="阅读区块切换">
        <button
          type="button"
          class="flex w-full items-center justify-between rounded-md px-3 py-2 text-left text-sm transition-colors"
          :class="activeSection === 'posts' ? 'bg-primary/15 text-highlighted' : 'text-muted hover:bg-elevated/50'"
          @click="activeSection = 'posts'"
        >
          <span>文章</span>
          <span class="text-xs tabular-nums">{{ postsTotal }}</span>
        </button>
        <button
          type="button"
          class="flex w-full items-center justify-between rounded-md px-3 py-2 text-left text-sm transition-colors"
          :class="activeSection === 'timeline' ? 'bg-primary/15 text-highlighted' : 'text-muted hover:bg-elevated/50'"
          @click="activeSection = 'timeline'"
        >
          <span>时光机</span>
          <span class="text-xs tabular-nums">{{ timelineTotal }}</span>
        </button>
        <button
          type="button"
          class="flex w-full items-center justify-between rounded-md px-3 py-2 text-left text-sm transition-colors"
          :class="activeSection === 'reading' ? 'bg-primary/15 text-highlighted' : 'text-muted hover:bg-elevated/50'"
          @click="activeSection = 'reading'"
        >
          <span>阅读</span>
          <span class="text-xs tabular-nums">{{ readingTotal }}</span>
        </button>
      </nav>
    </aside>

    <section class="min-w-0">
      <div v-if="activeSection === 'posts'" class="space-y-4">
        <h2 class="text-lg font-semibold text-highlighted">
          文章
        </h2>
        <div v-if="postsPending" class="text-sm text-muted">
          加载中…
        </div>
        <UEmpty v-else-if="!postsData?.total" title="暂无公开文章" />
        <template v-else>
          <NuxtLink
            v-for="(p, i) in postsData.items"
            :key="`${postSlug(p)}-${i}`"
            :to="`/@${slug}/posts/${encodeURIComponent(postSlug(p))}`"
            class="block rounded-xl border border-default/80 bg-elevated/20 px-4 py-4"
          >
            <div class="font-semibold text-highlighted">
              {{ postTitle(p) }}
            </div>
            <p v-if="postExcerpt(p)" class="mt-2 text-sm text-muted line-clamp-3">
              {{ postExcerpt(p) }}
            </p>
          </NuxtLink>
          <div v-if="postsData.total > 10" class="flex justify-end">
            <UPagination
              :page="postsPage"
              :total="postsData.total"
              :items-per-page="10"
              size="sm"
              @update:page="postsPage = $event"
            />
          </div>
        </template>
      </div>

      <div v-else-if="activeSection === 'timeline'" class="space-y-4">
        <h2 class="text-lg font-semibold text-highlighted">
          时光机
        </h2>
        <div v-if="timelinePending" class="text-sm text-muted">
          加载中…
        </div>
        <UEmpty v-else-if="!timelineData?.total" title="暂无公开动态" />
        <template v-else>
          <article
            v-for="(e, i) in timelineData.items"
            :key="timelineKey(e, i)"
            class="rounded-xl border border-default/80 bg-elevated/20 px-4 py-4"
          >
            <div class="flex items-start justify-between gap-3">
              <h3 class="font-semibold text-highlighted">
                {{ timelineTitle(e) }}
              </h3>
              <time
                v-if="e.occurredOn"
                class="text-xs tabular-nums text-muted"
                :datetime="occurredOnToIsoAttr(e.occurredOn)"
              >{{ formatOccurredOnDisplay(e.occurredOn) }}</time>
            </div>
            <p v-if="timelineBody(e)" class="mt-2 whitespace-pre-wrap text-sm text-muted">
              {{ timelineBody(e) }}
            </p>
            <a
              v-if="timelineHref(e)"
              :href="timelineHref(e)"
              target="_blank"
              rel="noopener noreferrer"
              class="mt-2 inline-flex text-sm text-primary hover:underline"
            >
              打开链接
            </a>
          </article>
          <div v-if="timelineData.total > 10" class="flex justify-end">
            <UPagination
              :page="timelinePage"
              :total="timelineData.total"
              :items-per-page="10"
              size="sm"
              @update:page="timelinePage = $event"
            />
          </div>
        </template>
      </div>

      <div v-else class="space-y-4">
        <h2 class="text-lg font-semibold text-highlighted">
          阅读
        </h2>
        <div v-if="readingPending" class="text-sm text-muted">
          加载中…
        </div>
        <UEmpty v-else-if="!readingData?.total" title="暂无公开阅读条目" />
        <template v-else>
          <template v-for="(it, i) in readingData.items" :key="i">
            <a
              v-if="readingHref(it)"
              :href="readingHref(it)"
              target="_blank"
              rel="noopener noreferrer"
              class="block rounded-xl border border-default/80 bg-elevated/20 px-4 py-4"
            >
              <div class="font-semibold text-highlighted">
                {{ readingTitle(it) }}
              </div>
              <div class="mt-2 text-sm text-muted">
                {{ readingHost(readingHref(it)) }}
              </div>
            </a>
            <div v-else class="rounded-xl border border-default/80 bg-elevated/20 px-4 py-4">
              <div class="font-semibold text-highlighted">
                {{ readingTitle(it) }}
              </div>
            </div>
          </template>
          <div v-if="readingData.total > 10" class="flex justify-end">
            <UPagination
              :page="readingPage"
              :total="readingData.total"
              :items-per-page="10"
              size="sm"
              @update:page="readingPage = $event"
            />
          </div>
        </template>
      </div>
    </section>
  </div>
</template>
