<script setup lang="ts">
import {
  computed,
  onMounted,
  ref,
  useTemplateRef,
} from 'vue'
import PrimeVueCarousel from 'primevue/carousel'
import PrimeVueImage from 'primevue/image'
import { marked } from 'marked'
import type { 
  GalleryEntry,
  GalleryEntryWithVariants,
  GalleryEntryWithoutVariants,
  GalleryListDefinition,
  ListWithEntries,
  RoutedWindow,
} from '@goldenwere/mackenzii-types'

import { fetchAndParseConfig, fetchConfigByIdFromList } from 'src/utilities/fetch'
import { getCurrentRoute } from 'src/utilities/vuetils'
import { useRouteStore } from 'src/routes'

import EmbedableContent from 'src/components/shared/embedable-content.vue'

declare const window: RoutedWindow

const emits = defineEmits<{
  (e: 'loaded'): void
}>()

const imageRef = useTemplateRef<HTMLImageElement>('image-ref' as any)
const ready = ref(false)
const resolved = ref({} as GalleryEntry)
const currentRoute = getCurrentRoute()
const routeStore = useRouteStore()
const routeConfig = routeStore._routes[currentRoute.path.substring(0, currentRoute.path.length - 5)] as GalleryListDefinition
const routeSubConfig = routeStore._routes[currentRoute.path]
const description = computed(() => marked.parse(resolved.value.description || '') as string)
const title = computed(() => marked.parse(resolved.value.title || currentRoute.query.id!.toString()) as string)
const url = computed(() => (resolved.value as GalleryEntryWithoutVariants).url)
const fields = computed(() => {
  const toReturn = {} as Record<string, any>
  if (!!resolved.value.date) {
    toReturn.date = resolved.value.date
  }
  if (!!resolved.value.warnings) {
    toReturn.warnings = resolved.value.warnings
  }
  return toReturn
})
const variants = computed(() => (resolved.value as GalleryEntryWithVariants).variants)
const currentSelection = defineModel('currentSelection', { type: Number, default: 0 })
const currentUrl = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value]?.url)
const currentAlt = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value]?.alternativeText)
const currentCaption = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value]?.caption)
const carouselResponsiveOptions = [
  {
    breakpoint: '800px',
    numVisible: 3,
    numScroll: 1,
  },
]

const onVariantSelected = (event: Event, id: number) => {
  if (id === currentSelection.value) {
    return
  }

  // prevent resizing from image swap by storing the previous width/height
  if (!!imageRef.value) {
    imageRef.value.style.width = `${imageRef.value.clientWidth}px`
    imageRef.value.style.height = `${imageRef.value.clientHeight}px`
  }

  // remove the image for a frame so that it won't get stuck on the old one while the new one loads
  currentSelection.value = -1
  requestAnimationFrame(() => {
    currentSelection.value = id

    // allow a second for the image to load before unsetting the width/height
    setTimeout(() => {
      if (!!imageRef.value) {
        imageRef.value.style.width = `unset`
        imageRef.value.style.height = `unset`
      }
    }, 1000)
  })
}

onMounted(async () => {
  let config = await fetchAndParseConfig<ListWithEntries<GalleryEntry>>(routeConfig.config)
  resolved.value = await fetchConfigByIdFromList(config, currentRoute.query.id as string)
  document.title = routeSubConfig.fullTitle?.replace('$ENTRY', resolved.value.title || currentRoute.query.id as string)
  routeStore.setBreadcrumbs(currentRoute, resolved.value.title || currentRoute.query.id as string)
  window.routeConfig = {...routeConfig}
  window.routeSubConfig = {...routeSubConfig}
  window.routeContentConfig = {...resolved.value}
  currentSelection.value = (resolved.value as GalleryEntryWithVariants).defaultVariant || 0
  ready.value = true
  emits('loaded')
})
</script>

<template lang="pug">
.template.gallery-view
  Transition
    .view-wrapper(
      v-if='ready'
    )
      .view-outlet
        .image-wrapper(
          ref='image-ref'
        )
          PrimeVueImage(
            :src='currentUrl'
            :title='currentCaption || currentAlt || description'
            :alt='currentAlt || currentCaption || description'
            preview
          )
        PrimeVueCarousel(
          :value='variants'
          :numVisible='5'
          :numScroll='5'
          :responsiveOptions='carouselResponsiveOptions'
        )
          template(
            #item='slotProps'
          )
            img(
              :class='{ active: slotProps.index === currentSelection }'
              :alt='slotProps.data.alternativeText || slotProps.data.caption || description'
              :src='slotProps.data.thumbnailUrl || slotProps.data.url'
              :title='slotProps.data.caption || slotProps.index'
              @click='onVariantSelected($event, slotProps.index)'
            )
      .view-content
        p.title(
          v-html='title'
        )
        dl.info
          .info-entry(
            v-for='(field, key) in fields'
            :class='key'
          )
            dt {{ key }}
            dd {{ field }}
        EmbedableContent(
          :content='description'
        )
</template>

<style lang="sass">
.p-carousel
  img
    cursor: pointer
    max-width: 100%
</style>
