<script setup>
const { data: posts } = await useFetch('/api/posts', {
  default: () => []
})

const { data: tags } = await useFetch('/api/tags', {
  default: () => []
})

const { data: siteSettings } = await useFetch('/api/site-settings', {
  default: () => ({})
})

const postFeedStyleStorageKey = 'POST_FEED_STYLE'

const postFeedStyleOpen = ref(false)
const postFeedStyle = ref('compact')

/** @typedef {'list' | 'compact' | 'cards'} PostFeedStyle */

/**
 * 저장·표시용 피드 보기 방식을 정규화한다.
 * @param {string|null|undefined} value - 원본 값
 * @returns {PostFeedStyle}
 */
const normalizePostFeedStyle = (value) => {
  if (value === 'list' || value === 'cards') {
    return value
  }

  return 'compact'
}

/**
 * Latest 피드 보기 방식을 저장한다.
 * @param {'list' | 'compact' | 'cards' | 'articles'} value - 보기 방식
 * @returns {void}
 */
const setPostFeedStyle = (value) => {
  const nextStyle = normalizePostFeedStyle(value === 'articles' ? 'compact' : value)
  postFeedStyle.value = nextStyle

  if (import.meta.client) {
    localStorage.setItem(postFeedStyleStorageKey, nextStyle)
  }
}

/** @type {import('vue').ComputedRef<boolean>} */
const isPostFeedCards = computed(() => postFeedStyle.value === 'cards')

/** @type {import('vue').ComputedRef<boolean>} */
const showPostFeedMedia = computed(() => postFeedStyle.value === 'compact' || postFeedStyle.value === 'cards')

/**
 * Latest 피드 컨테이너 클래스
 * @param {PostFeedStyle} style - 보기 방식
 * @returns {string}
 */
const getPostFeedContainerClass = (style) => {
  if (style === 'cards') {
    return 'post-feed post-feed--cards mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2'
  }

  return 'post-feed post-feed--stack flex flex-col divide-y divide-[var(--site-line)]'
}

/**
 * Latest 게시물 카드 클래스
 * @param {PostFeedStyle} style - 보기 방식
 * @returns {string}
 */
const getPostFeedArticleClass = (style) => {
  if (style === 'cards') {
    return 'post-feed__card group relative flex flex-col rounded-[10px] border border-[var(--site-line)] bg-[var(--site-bg)] p-3'
  }

  if (style === 'compact') {
    return 'post-feed__item post-feed__item--compact group relative flex flex-row gap-3 py-3'
  }

  return 'post-feed__item post-feed__item--list group relative flex flex-row gap-3 py-4'
}

/**
 * 요약 줄 수 클래스
 * @param {PostFeedStyle} style - 보기 방식
 * @returns {string}
 */
const getPostFeedExcerptClass = (style) => {
  if (style === 'list') {
    return 'post-summary-clamp post-summary-clamp--three'
  }

  return 'post-summary-clamp post-summary-clamp--two'
}

const closePostFeedStyleMenu = () => {
  postFeedStyleOpen.value = false
}

const onDocumentPointerDown = (event) => {
  if (!postFeedStyleOpen.value) {
    return
  }

  const target = /** @type {HTMLElement | null} */ (event.target instanceof HTMLElement ? event.target : null)
  if (!target) {
    closePostFeedStyleMenu()
    return
  }

  if (target.closest('[data-feed-style-root]')) {
    return
  }

  closePostFeedStyleMenu()
}

/**
 * 태그 슬러그로 태그 정보 조회
 * @param {string | undefined} slug - 태그 슬러그
 * @returns {{name: string, color: string}} 태그 정보
 */
const getTagMeta = (slug) => {
  if (!slug) {
    return {
      name: '',
      color: '#4d4d4d'
    }
  }

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

  return {
    name: matchedTag?.name || String(slug).toUpperCase(),
    color: matchedTag?.color || '#4d4d4d'
  }
}

/**
 * Latest 목록 데이터 변환
 * @param {Object} post - API 게시물
 * @returns {Object} 화면 표시 데이터
 */
const mapLatestPost = (post) => {
  const primaryTagSlug = post.tags?.[0]
  const tagMeta = getTagMeta(primaryTagSlug)

  return {
    title: post.title,
    excerpt: createPostSummary(post.excerpt, post.content, {
      maxLength: 320,
      appendEllipsis: false
    }),
    featuredImage: post.featuredImage,
    tagName: tagMeta.name,
    tagColor: tagMeta.color,
    publishedAt: formatPostDate(post.publishedAt),
    publishedAtIso: post.publishedAt || '',
    to: `/post/${post.slug}`,
    isFeatured: Boolean(post.isFeatured),
    commentCount: Number(post.commentCount || 0)
  }
}

const featuredPosts = computed(() => posts.value.filter((post) => post.isFeatured).slice(0, 6))
const latestPosts = computed(() => posts.value.map(mapLatestPost))

const featuredTrackRef = ref(null)
/** Featured 트랙이 스크롤 시작에 붙었는지 — 이전 화살표 비활성 */
const featuredAtStart = ref(true)
/** Featured 트랙이 스크롤 끝에 붙었는지 — 다음 화살표 비활성 */
const featuredAtEnd = ref(true)

let unbindFeaturedScroll = () => {}

/**
 * Featured 가로 스크롤 위치에 따라 이전/다음 버튼 상태를 갱신한다.
 * @param {HTMLElement | null} el - 스크롤 컨테이너
 * @returns {void}
 */
const updateFeaturedScrollEdges = (el) => {
  const target = el || featuredTrackRef.value

  if (!target) {
    featuredAtStart.value = true
    featuredAtEnd.value = true
    return
  }

  const { scrollLeft, scrollWidth, clientWidth } = target
  const maxScroll = Math.max(0, scrollWidth - clientWidth)
  const epsilon = 2

  featuredAtStart.value = scrollLeft <= epsilon
  featuredAtEnd.value = scrollLeft >= maxScroll - epsilon
}

watch(featuredTrackRef, (el) => {
  unbindFeaturedScroll()
  unbindFeaturedScroll = () => {}

  if (!import.meta.client || !el) {
    updateFeaturedScrollEdges(null)
    return
  }

  const onScroll = () => {
    updateFeaturedScrollEdges(el)
  }

  onScroll()
  el.addEventListener('scroll', onScroll, { passive: true })
  const resizeObserver = new ResizeObserver(onScroll)
  resizeObserver.observe(el)
  unbindFeaturedScroll = () => {
    el.removeEventListener('scroll', onScroll)
    resizeObserver.disconnect()
  }
}, { immediate: true })

watch(featuredPosts, () => {
  if (!import.meta.client) {
    return
  }

  nextTick(() => {
    updateFeaturedScrollEdges(featuredTrackRef.value)
  })
})

onMounted(() => {
  if (!import.meta.client) {
    return
  }

  const storedStyle = localStorage.getItem(postFeedStyleStorageKey)
  postFeedStyle.value = normalizePostFeedStyle(storedStyle)

  document.addEventListener('pointerdown', onDocumentPointerDown)
})

onBeforeUnmount(() => {
  if (!import.meta.client) {
    return
  }

  unbindFeaturedScroll()
  document.removeEventListener('pointerdown', onDocumentPointerDown)
})

/**
 * Featured 가로 트랙을 좌우로 이동한다.
 * @param {'left' | 'right'} direction - 이동 방향
 * @returns {void}
 */
const scrollFeatured = (direction) => {
  if (!featuredTrackRef.value) {
    return
  }

  if (direction === 'left' && featuredAtStart.value) {
    return
  }

  if (direction === 'right' && featuredAtEnd.value) {
    return
  }

  const firstCard = featuredTrackRef.value.querySelector('[data-featured-slide]')
  const cardWidth = firstCard ? firstCard.getBoundingClientRect().width : 244
  const gap = 24
  const offset = direction === 'left' ? -(cardWidth + gap) : cardWidth + gap

  featuredTrackRef.value.scrollBy({
    left: offset,
    behavior: 'smooth'
  })
}
</script>

<template>
  <MainColumn>
    <section v-if="siteSettings?.homeCoverImageUrl || siteSettings?.homeCoverDarkImageUrl" class="home-page__hero">
      <HomeHero
        :image-url="siteSettings.homeCoverImageUrl"
        :dark-image-url="siteSettings.homeCoverDarkImageUrl"
        :title="siteSettings.homeCoverTitle"
        :text="siteSettings.homeCoverText"
      />
    </section>

    <section v-if="featuredPosts.length" class="py-4 px-6">
      <div class="mx-auto max-w-[720px]">
        <div class="flex items-end justify-between gap-2 border-b border-[var(--site-line)] pb-2">
          <h2 class="text-sm font-medium uppercase site-muted">Featured</h2>
          <div class="flex justify-between gap-2">
            <button
              class="featured-nav-prev cursor-pointer p-1 text-[var(--site-text)] hover:opacity-75 disabled:cursor-not-allowed disabled:opacity-35 disabled:hover:opacity-35"
              type="button"
              aria-label="Featured 이전"
              :disabled="featuredAtStart"
              @click="scrollFeatured('left')"
            >
              ‹
            </button>
            <button
              class="featured-nav-next cursor-pointer p-1 text-[var(--site-text)] hover:opacity-75 disabled:cursor-not-allowed disabled:opacity-35 disabled:hover:opacity-35"
              type="button"
              aria-label="Featured 다음"
              :disabled="featuredAtEnd"
              @click="scrollFeatured('right')"
            >
              ›
            </button>
          </div>
        </div>
        <div
          ref="featuredTrackRef"
          class="featured-posts-track mt-4 flex snap-x snap-mandatory gap-6 overflow-x-auto overscroll-x-contain scroll-smooth pb-1 touch-pan-x [-webkit-overflow-scrolling:touch] [--slides:1.4] sm:[--slides:1.6] lg:[--slides:2.6] [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
        >
          <NuxtLink
            v-for="post in featuredPosts"
            :key="`featured-${post.slug}`"
            :to="`/post/${post.slug}`"
            class="group relative block aspect-video w-[calc((100%-(24px*(var(--slides)-1)))/var(--slides))] shrink-0 snap-start overflow-hidden rounded-[10px]"
            data-featured-slide
          >
            <img
              v-if="post.featuredImage"
              :src="post.featuredImage"
              :alt="post.title"
              class="h-full w-full object-cover brightness-75 contrast-125 transition-all duration-200 group-hover:brightness-90 group-hover:contrast-110"
              loading="lazy"
            >
            <div
              v-else
              class="post-card-media__placeholder flex h-full w-full items-center justify-center bg-[#F7F4EF] p-5 text-center text-sm font-medium leading-snug text-[var(--site-muted)] transition-all duration-200 group-hover:opacity-90"
              :aria-label="post.title"
            >
              <span class="post-card-media__placeholder-text line-clamp-4">{{ post.title }}</span>
            </div>
            <h3 v-if="post.featuredImage" class="absolute right-0 bottom-2.5 left-0 px-3 text-sm font-medium leading-tight text-white line-clamp-2">
              {{ post.title }}
            </h3>
          </NuxtLink>
        </div>
      </div>
    </section>

    <section class="latest-posts-section min-h-[360px] py-4 px-6">
      <div class="mx-auto max-w-[720px]">
        <div class="flex items-end justify-between gap-2 border-b border-[var(--site-line)] pb-2">
          <h2 class="text-sm font-medium uppercase site-muted">Latest</h2>
          <div class="relative flex flex-col gap-1 text-sm font-medium" data-feed-style-root>
            <button
              class="site-input relative flex cursor-pointer items-center justify-center gap-1 rounded-[10px] border px-2 py-1.5 pr-1.5 leading-none hover:bg-[var(--site-panel)]"
              type="button"
              aria-label="피드 보기 방식 선택"
              data-feed-style-toggle
              @click="postFeedStyleOpen = !postFeedStyleOpen"
            >
              <span class="pointer-events-none" v-show="postFeedStyle === 'list'">
                <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                  <path d="M9 6h11" />
                  <path d="M9 12h11" />
                  <path d="M9 18h11" />
                  <path d="M5 6v.01" />
                  <path d="M5 12v.01" />
                  <path d="M5 18v.01" />
                </svg>
              </span>
              <span class="pointer-events-none" v-show="postFeedStyle === 'compact'">
                <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                  <path d="M13 5h8" />
                  <path d="M13 9h5" />
                  <path d="M13 15h8" />
                  <path d="M13 19h5" />
                  <path d="M3 5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5" />
                  <path d="M3 15a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-4" />
                </svg>
              </span>
              <span class="pointer-events-none" v-show="postFeedStyle === 'cards'">
                <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                  <path d="M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6" />
                  <path d="M4 16a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-2" />
                </svg>
              </span>
              <span class="pointer-events-none opacity-75">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                  <path d="m6 9 6 6 6-6" />
                </svg>
              </span>
            </button>

            <menu
              class="absolute top-9 right-0 z-10 flex w-44 flex-col gap-0.5 rounded-[10px] border border-[var(--site-line)] bg-[var(--site-bg)] p-1.5 shadow transition-[transform,opacity,visibility,scale] duration-200"
              :class="postFeedStyleOpen ? 'visible translate-y-0 scale-100 opacity-100' : 'invisible -translate-y-3 scale-95 opacity-0'"
            >
              <li class="w-full">
                <button class="flex w-full cursor-pointer items-center gap-1.5 rounded-[10px] px-2 py-1 hover:bg-[var(--site-panel)]" type="button" @click="setPostFeedStyle('list'); closePostFeedStyleMenu()">
                  <span class="pointer-events-none">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                      <path d="M9 6h11" />
                      <path d="M9 12h11" />
                      <path d="M9 18h11" />
                      <path d="M5 6v.01" />
                      <path d="M5 12v.01" />
                      <path d="M5 18v.01" />
                    </svg>
                  </span>
                  <span>List</span>
                </button>
              </li>
              <li class="w-full">
                <button class="flex w-full cursor-pointer items-center gap-1.5 rounded-[10px] px-2 py-1 hover:bg-[var(--site-panel)]" type="button" @click="setPostFeedStyle('compact'); closePostFeedStyleMenu()">
                  <span class="pointer-events-none">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                      <path d="M13 5h8" />
                      <path d="M13 9h5" />
                      <path d="M13 15h8" />
                      <path d="M13 19h5" />
                      <path d="M3 5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5" />
                      <path d="M3 15a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-4" />
                    </svg>
                  </span>
                  <span>Compact</span>
                </button>
              </li>
              <li class="w-full">
                <button class="flex w-full cursor-pointer items-center gap-1.5 rounded-[10px] px-2 py-1 hover:bg-[var(--site-panel)]" type="button" @click="setPostFeedStyle('cards'); closePostFeedStyleMenu()">
                  <span class="pointer-events-none">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                      <path d="M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6" />
                      <path d="M4 16a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-2" />
                    </svg>
                  </span>
                  <span>Cards</span>
                </button>
              </li>
              <li class="w-full">
                <button class="flex w-full cursor-pointer items-center gap-1.5 rounded-[10px] px-2 py-1 hover:bg-[var(--site-panel)]" type="button" @click="setPostFeedStyle('compact'); closePostFeedStyleMenu()">
                  <span class="pointer-events-none">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                      <path d="M3.06 13a9 9 0 1 0 .49-4.087" />
                      <path d="M3 4.001v5h5" />
                      <path d="M11 12a1 1 0 1 0 2 0a1 1 0 1 0-2 0" />
                    </svg>
                  </span>
                  <span>Default</span>
                </button>
              </li>
            </menu>
          </div>
        </div>
        <div class="post-feed-section mb-8 flex flex-col">
          <div
            class="post-feed-section__list"
            data-post-feed="latest"
            :class="getPostFeedContainerClass(postFeedStyle)"
          >
            <article
              v-for="post in latestPosts"
              :key="post.to"
              data-post-card
              :data-featured="post.isFeatured ? '' : undefined"
              :class="getPostFeedArticleClass(postFeedStyle)"
            >
              <PostCardMedia
                v-if="showPostFeedMedia"
                :to="post.to"
                :title="post.title"
                :featured-image="post.featuredImage"
                :link-class="isPostFeedCards ? 'post-feed__media post-feed__media--cards mb-3 block aspect-video w-full' : 'post-feed__media post-feed__media--list relative flex-1 aspect-square min-w-16 sm:aspect-video'"
                :aspect-class="isPostFeedCards ? 'aspect-video' : 'aspect-square sm:aspect-video'"
              />

              <div
                class="post-feed__content relative min-w-0"
                :class="isPostFeedCards ? 'flex flex-col' : 'flex flex-[3] flex-col gap-1.5 md:flex-[4]'"
              >
                <div class="post-feed__content-inner flex min-h-0 flex-1 flex-col gap-1">
                  <h2 class="max-w-[90%] text-sm font-medium leading-tight">
                    <NuxtLink :to="post.to" class="flex items-center transition-opacity duration-200 hover:opacity-75">
                      <span v-if="post.isFeatured" class="post-feed__featured-icon mr-1 inline-flex h-4 w-4 items-center justify-center text-[var(--site-accent)]">
                        <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
                          <path d="M13 3v7h6l-8 11v-7H5l8-11" />
                        </svg>
                      </span>
                      {{ post.title }}
                    </NuxtLink>
                  </h2>

                  <p
                    v-if="post.excerpt"
                    class="flex-1 text-[0.8rem] leading-tight site-muted text-[#6E6661]"
                    :class="getPostFeedExcerptClass(postFeedStyle)"
                  >
                    {{ post.excerpt }}
                  </p>

                  <div class="flex flex-wrap items-center gap-2 text-xs site-muted sm:gap-1.5">
                    <time v-if="post.publishedAt" :datetime="post.publishedAtIso">{{ post.publishedAt }}</time>
                    <template v-if="post.tagName">
                      <span v-if="post.publishedAt" class="text-[var(--site-line)]">/</span>
                      <span
                        class="rounded-md px-1.5 py-px font-medium text-[var(--site-text)]"
                        :style="{ backgroundColor: `${post.tagColor}1a` }"
                      >
                        {{ post.tagName }}
                      </span>
                    </template>
                    <span v-if="post.publishedAt || post.tagName" class="text-[var(--site-line)]">/</span>
                    <span class="flex items-center gap-1">
                      <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>{{ post.commentCount }}</span>
                    </span>
                  </div>
                </div>

                <button
                  class="absolute top-0 right-0 flex cursor-pointer items-center gap-1 hover:opacity-75"
                  :class="isPostFeedCards ? '' : 'md:top-auto md:right-0 md:bottom-0 md:invisible md:opacity-0 md:transition-[opacity,visibility] md:duration-200 md:group-hover:visible md:group-hover:opacity-100'"
                  type="button"
                  aria-label="Share this post"
                >
                  <svg
                    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="M17 7 7 17" />
                    <path d="M8 7h9v9" />
                  </svg>
                </button>
              </div>
            </article>
          </div>
        </div>
      </div>
    </section>
  </MainColumn>
</template>
