<script setup>
import {
  ANNOUNCEMENT_SNOOZE_DAYS,
  dismissAnnouncementForDays,
  dismissAnnouncementForSession,
  getAnnouncementBarTextColor,
  isAnnouncementDismissed,
  normalizeAnnouncementUrl
} from '~/lib/announcement-bar.js'

/** @type {number} 슬라이드 애니메이션 시간(ms) */
const SLIDE_MS = 320

const { data: siteSettings } = await useFetch('/api/site-settings', {
  default: () => ({
    announcementEnabled: false,
    announcementText: '',
    announcementUrl: '',
    announcementBackgroundColor: '#15171a',
    updatedAt: null
  })
})

/** DOM에 바를 둘지(애니메이션 종료 전까지 유지) */
const inDom = ref(false)
/** 펼침(아래로 슬라이드) 애니메이션 상태 */
const expanded = ref(false)
/** 숨김 처리 완료 여부 */
const dismissed = ref(false)

let closeTimer = null

/**
 * 설정상 어나운스 바를 켤 수 있는지
 * @returns {boolean} 가능 여부
 */
const isEligible = computed(() => {
  if (!siteSettings.value?.announcementEnabled) {
    return false
  }

  return Boolean((siteSettings.value?.announcementText || '').trim())
})

const announcementText = computed(() => (siteSettings.value?.announcementText || '').trim())

const announcementLink = computed(() => normalizeAnnouncementUrl(siteSettings.value?.announcementUrl || ''))

const snoozeLabel = computed(() => `${ANNOUNCEMENT_SNOOZE_DAYS}일간 보지 않기`)

const barStyle = computed(() => {
  const backgroundColor = siteSettings.value?.announcementBackgroundColor || '#15171a'
  return {
    backgroundColor,
    color: getAnnouncementBarTextColor(backgroundColor)
  }
})

/**
 * 어나운스 바를 펼친다.
 * @returns {Promise<void>}
 */
const openBar = async () => {
  inDom.value = true
  expanded.value = false
  await nextTick()
  requestAnimationFrame(() => {
    requestAnimationFrame(() => {
      expanded.value = true
    })
  })
}

/**
 * 어나운스 바를 접고 DOM에서 제거한다.
 * @param {() => void} persistDismiss - localStorage·sessionStorage 저장
 * @returns {void}
 */
const closeBar = (persistDismiss) => {
  if (!inDom.value) {
    return
  }

  persistDismiss()
  expanded.value = false

  if (closeTimer) {
    clearTimeout(closeTimer)
  }

  closeTimer = setTimeout(() => {
    inDom.value = false
    dismissed.value = true
    closeTimer = null
  }, SLIDE_MS)
}

/**
 * 이번 방문(세션) 동안만 닫는다.
 * @returns {void}
 */
const dismissForSession = () => {
  closeBar(() => dismissAnnouncementForSession(siteSettings.value))
}

/**
 * N일간 보지 않기로 닫는다.
 * @returns {void}
 */
const dismissForSnooze = () => {
  closeBar(() => dismissAnnouncementForDays(siteSettings.value))
}

watch(() => siteSettings.value?.updatedAt, async () => {
  if (!import.meta.client) {
    return
  }

  const hidden = isAnnouncementDismissed(siteSettings.value)
  dismissed.value = hidden

  if (!isEligible.value || hidden) {
    expanded.value = false
    inDom.value = false
    return
  }

  await openBar()
})

onMounted(() => {
  dismissed.value = isAnnouncementDismissed(siteSettings.value)

  if (isEligible.value && !dismissed.value) {
    openBar()
  }
})

onBeforeUnmount(() => {
  if (closeTimer) {
    clearTimeout(closeTimer)
  }
})
</script>

<template>
  <div
    v-if="inDom"
    class="site-announcement-bar-shell grid transition-[grid-template-rows] duration-300 ease-out motion-reduce:transition-none"
    :class="expanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'"
    :style="{ transitionDuration: `${SLIDE_MS}ms` }"
  >
    <div class="min-h-0 overflow-hidden">
      <div
        class="site-announcement-bar relative z-30 w-full text-center text-sm font-medium"
        :style="barStyle"
        role="region"
        aria-label="사이트 공지"
        :aria-hidden="(!expanded).toString()"
      >
        <div class="site-announcement-bar__inner relative mx-auto flex min-h-9 max-w-[1294px] items-center justify-center gap-3 px-4 py-2.5 sm:px-6 lg:px-8">
          <component
            :is="announcementLink ? 'a' : 'span'"
            class="site-announcement-bar__text min-w-0 flex-1 line-clamp-2 px-6 sm:px-8"
            :class="announcementLink ? 'hover:underline' : ''"
            :href="announcementLink || undefined"
            :target="announcementLink ? '_blank' : undefined"
            :rel="announcementLink ? 'noreferrer' : undefined"
          >
            {{ announcementText }}
          </component>
          <div class="site-announcement-bar__actions absolute top-1/2 right-3 flex shrink-0 -translate-y-1/2 items-center gap-2 sm:right-4 lg:right-5">
            <button
              class="site-announcement-bar__snooze whitespace-nowrap text-xs font-medium underline-offset-2 opacity-90 transition hover:underline hover:opacity-100 sm:text-[13px]"
              type="button"
              @click="dismissForSnooze"
            >
              {{ snoozeLabel }}
            </button>
            <button
              class="site-announcement-bar__close inline-flex size-7 items-center justify-center rounded-full opacity-80 transition hover:opacity-100"
              type="button"
              aria-label="이번 방문 동안 닫기"
              @click="dismissForSession"
            >
              <svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
                <path d="M18 6 6 18" />
                <path d="m6 6 12 12" />
              </svg>
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
