<script setup lang="ts">
import { formatDate } from 'date-fns'
import chestAnimation from '~/assets/images/chest.webp'
import { render } from 'vue'
import { CodeControls } from '#components'

const config = useAppConfig()
const router = useRouter()
const route = useRoute()

let slug = route.params.slug

if (Array.isArray(slug)) slug = slug.join('/')

const { data, status } = await useAsyncData('home', () =>
  queryContent(`/blog/${slug}`).findOne(),
)

const meta = {
  title: data.value ? data.value.title : 'Page not found',
  description: data.value
    ? data.value.description
    : 'The page you are looking for does not exist. It might have been removed, had its name changed, or is temporarily unavailable.',
  url: `${config.url}/blog`,
}

// When defineOgImage is used, useSeoMeta must exclude ogImage and twitterImage properties.
useSeoMeta({
  title: meta.title,
  description: meta.description,
  ogTitle: meta.title,
  ogDescription: meta.description,
  // ogImage: EXCLUDED
  ogUrl: meta.url,
  ogType: 'article',
  twitterTitle: meta.title,
  twitterDescription: meta.description,
  // twitterImage: EXCLUDED
  twitterCard: 'summary_large_image',
})

const clipboard = (el: HTMLElement) => {
  if (el.textContent)
    navigator.clipboard.writeText(el.textContent).catch(() => {
      console.error(
        'Failed to copy element data to the clipboard! Element data:',
        el,
      )
    })
}

const content = ref<Element | null>(null)
const thumbnail: string =
  data.value!.thumbnail ??
  `/images/blog/thumbnails/${data.value!._path!.split('/').at(-1)}.png`

// Generate the article's Open Graph image.
defineOgImageComponent(
  'ArticleThumbnail',
  {
    title: data.value!.title,
    description: data.value!.description,
    logo: '/images/logo.png',
    sectionLogo: '/images/chest.png',
    thumbnail,
    alt: data.value!.title,
  },
  {
    fonts: ['Alexandria:700', 'Lato:700'],
  },
)

// Hydrate the rendered items.
onMounted(() => {
  if (route.hash)
    content.value
      ?.querySelector(route.hash.toLowerCase())
      ?.scrollIntoView({ behavior: 'smooth' })

  content.value
    ?.querySelectorAll('code:not(pre *)')
    .forEach((code: Element) => {
      if (code instanceof HTMLElement)
        code.addEventListener('click', () => clipboard(code))
    })

  content.value?.querySelectorAll('pre').forEach((pre: HTMLPreElement) => {
    const overlay = h(CodeControls, { onCopy: () => clipboard(pre) })

    render(overlay, pre)
  })

  content.value?.querySelectorAll('a').forEach((a: HTMLAnchorElement) => {
    if (
      a.hash &&
      a.host === window.location.host &&
      a.pathname.toLowerCase() === route.path.toLowerCase()
    )
      a.addEventListener('click', (e: Event) => {
        e.preventDefault()

        content.value
          ?.querySelector(a.hash.toLowerCase())
          ?.scrollIntoView({ behavior: 'smooth' })

        history.replaceState(history.state, '', a.hash)
      })
  })
})

useHead({
  title: data.value!.title,
  htmlAttrs: {
    lang: config.locale || 'en',
  },
  link: [
    {
      rel: 'icon',
      type: 'image/x-icon',
      href: '/favicon.ico',
    },
  ],
})
</script>

<template>
  <div
    v-if="!data"
    class="flex flex-col items-center justify-center gap-4 w-full select-none text-center"
  >
    <img draggable="false" :src="chestAnimation" alt="The Ender Chest" />
    <div>
      <h1 class="font-enchant">Loading document...</h1>
      <span class="opacity-0 hover:opacity-100 transition-ease">
        <em>Loading document...</em>
      </span>
    </div>
  </div>
  <article
    v-else-if="data"
    class="flex-grow post snap-normal fade-mask-sm flex flex-col gap-4 overflow-y-auto sm:py-4 sm:pe-4"
  >
    <div class="grid-thumbnail grid max-w-[768px] snap-end">
      <img
        draggable="false"
        :src="thumbnail!"
        alt="Thumbnail"
        class="grid-thumbnail-image object-cover object-center rounded-xl aspect-[16/9] select-none"
      />
      <NuxtLink to="/blog" class="grid-thumbnail-start button-back p-2">
        <iconify-icon
          icon="icon-park-solid:back"
          width="2em"
          height="2em"
          class="drop-shadow text-pink-200"
        />
      </NuxtLink>
      <NuxtLink
        class="grid-thumbnail-end button-twitter p-2"
        :href="`https://twitter.com/share?url=${config.url}/blog/${slug}&text=${data.title}&hashtags=${data.tags.slice(0, 3).join(',').replace(/ /g, '')}`"
        target="_blank"
      >
        <iconify-icon
          icon="logos:twitter"
          width="2em"
          height="2em"
          class="drop-shadow"
        />
      </NuxtLink>
      <div
        class="grid-thumbnail-title accent-fade w-full rounded-b-lg p-2 mt-16"
      >
        <h3 class="mb-1">{{ data.title }}</h3>
        <div class="flex flex-row flex-wrap gap-x-2 gap-y-0">
          <small class="flex flex-row items-center gap-1 whitespace-nowrap">
            <iconify-icon icon="mdi:calendar" inline />
            <strong>
              {{ formatDate(data.created, 'HH:mm • LLLL do, y') }}
            </strong>
          </small>
          <small class="flex flex-row items-center gap-1 whitespace-nowrap">
            <iconify-icon icon="mdi:clock-outline" inline />
            <strong>
              {{ data!.readingTime.text.split(' ')[0] + ' minutes to read' }}
            </strong>
          </small>
        </div>
      </div>
    </div>
    <section ref="content" class="page snap-start">
      <ContentRenderer :value="data" />
    </section>
  </article>
  <NotFound v-else />
</template>

<style scoped lang="scss">
.grid-thumbnail {
  &-image {
    grid-column: 1;
    grid-row: 1;

    place-self: start center;

    max-width: clamp(1px, 100%, 768px);
    min-height: 100%;
  }

  &-title {
    grid-column: 1;
    grid-row: 1;

    place-self: end center;
  }

  &-start {
    grid-column: 1;
    grid-row: 1;

    place-self: start start;
  }

  &-end {
    grid-column: 1;
    grid-row: 1;

    place-self: start end;
  }
}
</style>
