<script setup>
definePageMeta({
  layout: 'post'
})

const route = useRoute()
const slug = computed(() => String(route.params.slug || ''))

const { data: post } = await useFetch(() => `/api/posts/${slug.value}`)
const { data: tags } = await useFetch('/api/tags', {
  default: () => []
})
const { data: posts } = await useFetch('/api/posts', {
  default: () => []
})
const { data: siteSettings } = await useFetch('/api/site-settings', {
  default: () => ({ showPostUpdatedAt: false })
})

if (!post.value) {
  throw createError({
    statusCode: 404,
    statusMessage: '게시물을 찾을 수 없습니다.'
  })
}

const primaryTagSlug = computed(() => post.value.tags?.[0] || '')
const primaryTagMeta = computed(() => {
  const slug = primaryTagSlug.value

  if (!slug) {
    return {
      name: '',
      color: '',
      to: '/tags'
    }
  }

  const matchedTag = tags.value.find((item) => item.slug === slug)

  return {
    name: matchedTag?.name || slug.toUpperCase(),
    color: matchedTag?.color || '#4d4d4d',
    to: `/tag/${slug}`
  }
})

const publishedAtLabel = computed(() => formatPostDate(post.value.publishedAt || null))
const updatedAtLabel = computed(() => {
  if (!siteSettings.value?.showPostUpdatedAt || !wasPostUpdatedAfterPublish(post.value)) {
    return ''
  }

  return `수정: ${formatPostDateTime(post.value.updatedAt)}`
})
const authorLabel = computed(() => 'sori.studio')
const shareModalOpen = ref(false)
const copyButtonLabel = ref('Copy link')

const currentIndex = computed(() => posts.value.findIndex((item) => item.slug === post.value.slug))
const previousPost = computed(() => {
  if (currentIndex.value <= 0) {
    return null
  }

  const candidate = posts.value[currentIndex.value - 1]
  return candidate ? { title: candidate.title, to: `/post/${candidate.slug}` } : null
})
const nextPost = computed(() => {
  if (currentIndex.value === -1 || currentIndex.value >= posts.value.length - 1) {
    return null
  }

  const candidate = posts.value[currentIndex.value + 1]
  return candidate ? { title: candidate.title, to: `/post/${candidate.slug}` } : null
})

const config = useRuntimeConfig()
const siteUrl = computed(() => String(config.public.siteUrl || '').replace(/\/$/g, ''))
const pageUrl = computed(() => `${siteUrl.value}/post/${post.value.slug}`)
const seoTitle = computed(() => post.value.seoTitle || post.value.title)
const seoDescription = computed(() => post.value.seoDescription || post.value.excerpt || 'sori.studio 개인 블로그')
const ogImage = computed(() => post.value.featuredImage || '')
const shareMetadata = computed(() => ({
  title: post.value.title || 'sori.studio',
  description: post.value.excerpt || 'sori.studio 개인 블로그',
  image: post.value.featuredImage || '',
  url: pageUrl.value
}))

const encodedShareText = computed(() => encodeURIComponent(shareMetadata.value.title))
const encodedShareUrl = computed(() => encodeURIComponent(shareMetadata.value.url))
const encodedShareSummary = computed(() => encodeURIComponent(shareMetadata.value.description))

const shareLinks = computed(() => [
  {
    id: 'x',
    label: 'Share on X',
    href: `https://twitter.com/share?text=${encodedShareText.value}&url=${encodedShareUrl.value}`
  },
  {
    id: 'bluesky',
    label: 'Share on Bluesky',
    href: `https://bsky.app/intent/compose?text=${encodedShareText.value}%20${encodedShareUrl.value}`
  },
  {
    id: 'facebook',
    label: 'Share on Facebook',
    href: `https://www.facebook.com/sharer.php?u=${encodedShareUrl.value}`
  },
  {
    id: 'linkedin',
    label: 'Share on Linkedin',
    href: `https://www.linkedin.com/shareArticle?mini=true&url=${encodedShareUrl.value}&title=${encodedShareText.value}&summary=${encodedShareSummary.value}`
  },
  {
    id: 'email',
    label: 'Share by email',
    href: `mailto:?subject=${encodedShareText.value}&body=${encodedShareUrl.value}`
  }
])

/**
 * 절대 URL 생성
 * @param {string} value - 원본 URL
 * @returns {string} 절대 URL
 */
const toAbsoluteUrl = (value) => {
  if (!value) {
    return ''
  }

  if (/^https?:\/\//i.test(value)) {
    return value
  }

  return `${siteUrl.value}${value.startsWith('/') ? value : `/${value}`}`
}

/**
 * 공유 모달을 연다.
 * @returns {void}
 */
const openShareModal = () => {
  shareModalOpen.value = true
}

/**
 * 공유 모달을 닫는다.
 * @returns {void}
 */
const closeShareModal = () => {
  shareModalOpen.value = false
}

/**
 * 게시물 URL을 클립보드에 복사한다.
 * @returns {Promise<void>}
 */
const copyShareLink = async () => {
  const url = shareMetadata.value.url

  try {
    if (import.meta.client && navigator.clipboard?.writeText) {
      await navigator.clipboard.writeText(url)
    } else if (import.meta.client) {
      const textarea = document.createElement('textarea')
      textarea.value = url
      textarea.setAttribute('readonly', '')
      textarea.style.position = 'absolute'
      textarea.style.left = '-9999px'
      document.body.appendChild(textarea)
      textarea.select()
      document.execCommand('copy')
      document.body.removeChild(textarea)
    }

    copyButtonLabel.value = 'Link copied!'
  } catch {
    copyButtonLabel.value = '복사 실패'
  }

  setTimeout(() => {
    copyButtonLabel.value = 'Copy link'
  }, 1800)
}

useHead(() => ({
  title: seoTitle.value,
  link: [
    {
      rel: 'canonical',
      href: pageUrl.value
    }
  ],
  meta: [
    {
      name: 'description',
      content: seoDescription.value
    },
    {
      name: 'robots',
      content: post.value.noindex ? 'noindex, nofollow' : 'index, follow'
    },
    {
      property: 'og:title',
      content: seoTitle.value
    },
    {
      property: 'og:description',
      content: seoDescription.value
    },
    {
      property: 'og:url',
      content: pageUrl.value
    },
    ...(ogImage.value
      ? [
          {
            property: 'og:image',
            content: toAbsoluteUrl(ogImage.value)
          },
          {
            name: 'twitter:card',
            content: 'summary_large_image'
          }
        ]
      : [])
  ]
}))
</script>

<template>
  <div class="post-detail">
    <section class="mt-6 mb-8">
      <div class="mx-auto flex max-w-[720px] flex-col gap-2.5 px-4 sm:px-5">
        <h1 class="text-xl font-semibold leading-[1.125] sm:text-2xl">
          {{ post.title }}
        </h1>

        <div class="relative border-b border-[var(--site-line)] pb-4">
          <div class="post-detail__meta flex flex-wrap items-center gap-2 text-xs site-muted sm:gap-1.5 [&>*]:after:content-['/'] [&>*]:after:ml-2 sm:[&>*]:after:ml-1.5 [&>*]:after:text-[var(--site-line)] [&>*:last-child]:after:hidden">
            <time v-if="publishedAtLabel" :datetime="post.publishedAt">
              {{ publishedAtLabel }}
            </time>

            <time v-if="updatedAtLabel" :datetime="post.updatedAt" class="admin-post-detail__updated-at">
              {{ updatedAtLabel }}
            </time>

            <a href="#" class="hover:opacity-75">
              {{ authorLabel }}
            </a>

            <ul v-if="primaryTagSlug" class="flex flex-wrap items-center font-medium">
              <li :style="{ '--color-accent': primaryTagMeta.color }">
                <NuxtLink
                  class="rounded-sm px-1.5 py-px text-[var(--site-text)] hover:opacity-75"
                  :style="{ backgroundColor: `${primaryTagMeta.color}1a` }"
                  :to="primaryTagMeta.to"
                >
                  {{ primaryTagMeta.name }}
                </NuxtLink>
              </li>
            </ul>

            <a class="flex items-center gap-1 hover:opacity-75" :href="`${pageUrl}#comments`">
              <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="-mt-px">
                <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
              </svg>
              <span class="pointer-events-none">{{ post.commentCount || 0 }}</span>
            </a>
          </div>

          <button class="absolute right-0 bottom-4 flex cursor-pointer items-center gap-1 hover:opacity-75" type="button" aria-label="Share this post" data-post-share-toggle @click="openShareModal">
            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <path d="M13 4v4c-6.575 1.028-9.02 6.788-10 12c-.037.206 5.384-5.962 10-6v4l8-7-8-7z" />
            </svg>
          </button>
        </div>

        <figure v-if="post.featuredImage" class="relative mt-2.5 w-full">
          <img
            class="aspect-video w-full rounded-[10px] object-cover bg-[var(--site-panel-strong)]"
            :src="post.featuredImage"
            :alt="post.title"
            loading="eager"
          >
        </figure>
      </div>
    </section>

    <section>
      <div class="mx-auto max-w-[720px] px-4 sm:px-5">
        <ContentRenderer>
          <ContentMarkdownRenderer class="post-detail__content" :content="post.content" />
        </ContentRenderer>
      </div>
    </section>

    <section id="comments" class="mt-12 mb-6 border-y border-[var(--site-line)] bg-[var(--site-panel-strong)] py-5 scroll-mt-14">
      <div class="mx-auto max-w-[720px] px-4 text-sm sm:px-5">
        <PostComments :slug="post.slug" />
      </div>
    </section>

    <section class="mb-6" aria-label="Previous and next post">
      <div class="mx-auto max-w-[720px] px-4 sm:px-5">
        <div class="grid gap-4 text-sm font-medium leading-tight md:grid-cols-2">
          <NuxtLink v-if="previousPost" :to="previousPost.to" class="flex flex-col items-start gap-1 hover:opacity-75">
            <span class="flex items-center gap-1 text-[0.7rem] font-medium uppercase opacity-75 site-muted">
              <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
                <path d="M15 6 9 12l6 6" />
              </svg>
              Previous post
            </span>
            <h3 class="ml-4 text-left">
              {{ previousPost.title }}
            </h3>
          </NuxtLink>
          <div v-else />

          <NuxtLink v-if="nextPost" :to="nextPost.to" class="flex flex-col items-end gap-1 hover:opacity-75">
            <span class="flex items-center gap-1 text-[0.7rem] font-medium uppercase opacity-75 site-muted">
              Next post
              <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
                <path d="m9 6 6 6-6 6" />
              </svg>
            </span>
            <h3 class="mr-4 text-right">
              {{ nextPost.title }}
            </h3>
          </NuxtLink>
        </div>
      </div>
    </section>

    <Transition
      enter-active-class="transition duration-200 ease-out"
      enter-from-class="opacity-0"
      enter-to-class="opacity-100"
      leave-active-class="transition duration-150 ease-in"
      leave-from-class="opacity-100"
      leave-to-class="opacity-0"
    >
      <div v-if="shareModalOpen" class="post-detail__share-modal fixed inset-0 z-40 flex items-center justify-center bg-[rgba(0,0,0,0.45)] px-4" @click.self="closeShareModal">
        <div class="relative mt-8 flex w-full max-w-[min(calc(100%-2rem),480px)] translate-y-0 scale-100 flex-col items-center rounded-[10px] bg-[var(--site-bg)] p-6 shadow-[0_20px_45px_rgba(0,0,0,0.18)]">
          <button class="absolute right-5 top-5 flex h-6 w-6 cursor-pointer items-center justify-center opacity-30 transition-opacity duration-200 hover:opacity-70" type="button" aria-label="Close share modal" @click="closeShareModal">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-4 w-4 fill-none stroke-current stroke-[1.2]">
              <path d="M.75 23.249l22.5-22.5M23.25 23.249L.75.749" />
            </svg>
          </button>

          <span class="mb-4 block self-start text-xs font-semibold uppercase tracking-wide site-muted">Share this post</span>

          <div class="mb-4 w-full overflow-hidden rounded-[10px] border border-[var(--site-line)]">
            <figure class="aspect-[2/1] w-full overflow-hidden bg-[var(--site-panel)]">
              <img
                v-if="shareMetadata.image"
                :src="shareMetadata.image"
                :alt="shareMetadata.title"
                class="h-full w-full object-cover"
              >
              <div v-else class="h-full w-full bg-[linear-gradient(135deg,#253444,#8f9dad)]" />
            </figure>
            <div class="flex flex-col gap-1.5 px-5 py-4">
              <h2 class="text-sm font-medium leading-tight md:text-base">
                {{ shareMetadata.title }}
              </h2>
              <p class="line-clamp-2 text-xs opacity-75 md:text-sm">
                {{ shareMetadata.description }}
              </p>
            </div>
          </div>

          <div class="flex w-full flex-wrap items-center gap-2 text-sm font-medium">
            <a
              v-for="item in shareLinks"
              :key="item.id"
              class="flex cursor-pointer items-center justify-center gap-1.5 rounded-[10px] border border-[var(--site-line)] bg-[var(--site-panel)] p-2 transition-opacity duration-200 hover:opacity-75 md:p-2.5"
              target="_blank"
              rel="noreferrer"
              :href="item.href"
              :title="item.label"
              aria-label="Share"
            >
              <svg
                v-if="item.id === 'x'"
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                class="h-4 w-4"
              >
                <path d="M4 4l11.733 16H20L8.267 4z" />
                <path d="M4 20l6.768-6.768m2.46-2.46L20 4" />
              </svg>
              <svg
                v-else-if="item.id === 'bluesky'"
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                class="h-4 w-4"
              >
                <path d="M6.335 5.144c-1.654 -1.199 -4.335 -2.127 -4.335 .826c0 .59 .35 4.953 .556 5.661c.713 2.463 3.13 2.75 5.444 2.369c-4.045 .665 -4.889 3.208 -2.667 5.41c1.03 1.018 1.913 1.59 2.667 1.59c2 0 3.134 -2.769 3.5 -3.5c.333 -.667 .5 -1.167 .5 -1.5c0 .333 .167 .833 .5 1.5c.366 .731 1.5 3.5 3.5 3.5c.754 0 1.637 -.571 2.667 -1.59c2.222 -2.203 1.378 -4.746 -2.667 -5.41c2.314 .38 4.73 .094 5.444 -2.369c.206 -.708 .556 -5.072 .556 -5.661c0 -2.953 -2.68 -2.025 -4.335 -.826c-2.293 1.662 -4.76 5.048 -5.665 6.856c-.905 -1.808 -3.372 -5.194 -5.665 -6.856z" />
              </svg>
              <svg
                v-else-if="item.id === 'facebook'"
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                class="h-4 w-4"
              >
                <path d="M7 10v4h3v7h4v-7h3l1-4h-4V8a1 1 0 0 1 1-1h3V3h-3a5 5 0 0 0-5 5v2z" />
              </svg>
              <svg
                v-else-if="item.id === 'linkedin'"
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                class="h-4 w-4"
              >
                <path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z" />
                <rect x="2" y="9" width="4" height="12" />
                <circle cx="4" cy="4" r="2" />
              </svg>
              <svg
                v-else
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="1.5"
                stroke-linecap="round"
                stroke-linejoin="round"
                class="h-4 w-4"
              >
                <rect x="3" y="5" width="18" height="14" rx="2" />
                <polyline points="3 7 12 13 21 7" />
              </svg>
              <span class="sr-only">{{ item.label }}</span>
            </a>

            <button
              class="flex flex-1 cursor-pointer items-center justify-center gap-1.5 rounded-[10px] border border-[var(--site-line)] bg-[var(--site-panel)] p-2 transition-opacity duration-200 hover:opacity-75 md:p-2.5"
              type="button"
              :title="copyButtonLabel"
              aria-label="Copy link"
              @click="copyShareLink"
            >
              <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4">
                <path d="M9 15l6 -6" />
                <path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" />
                <path d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" />
              </svg>
              <span>{{ copyButtonLabel }}</span>
            </button>
          </div>
        </div>
      </div>
    </Transition>
  </div>
</template>
