<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import type {
  ConfigfulRouteDefinition,
  ListWithTags,
  ListWithWarnings,
  MediaEntry,
  ResolvedListEntries,
} from '@goldenwere/mackenzii-types'
import { fetchAndParseConfig, fetchConfigsFromList, storage } from 'src/utilities/fetch'
import { getCurrentRoute } from 'src/utilities/vuetils'
import { useRouteStore } from 'src/routes'

import FilterPanel from 'src/components/shared/filter-panel.vue'
import GalleryTile from '../gallery/gallery-tile.vue'
import ArticleTile from '../article/article-tile.vue'

type MediaList =
  & ListWithTags<MediaEntry>
  & ListWithWarnings<MediaEntry>

/**
 * A wrapper around {@link ResolvedListEntries} for the app's use only which adds additional fields
 * in order for the app to effectively display the entries.
 */
type DisplayedEntries = ResolvedListEntries<MediaEntry & {
  /**
   * specifies whether the entry is hidden by the tags selected by a visitor
   */
  isHidden?: boolean
}>

const ready = ref(false)
const currentRoute = getCurrentRoute()
const routeStore = useRouteStore()
const routeConfig = routeStore._routes[currentRoute.path] as ConfigfulRouteDefinition

const globalConfig = routeStore._globals
const storageId = `${globalConfig.id}`
const viewPath = computed(() => `${currentRoute.path}/view`)

const config = ref(null as MediaList | null)
const entries = ref({} as DisplayedEntries)
const hasWarnings = ref(false)
const hideWarnings = defineModel('hideWarnings', { type: Boolean })
const template = ref(routeConfig.template)
const className = computed(() => {
  switch(template.value) {
    case 'gallery-list': {
      return 'gallery'
    }
    case 'article-list':
    default: {
      return 'article'
    }
  }
})

/**
 * Handler for a tag being selected;
 * updates the visibility state of the current entries
 * @param tagsToggled the tags currently toggled in the filter panel
 */
 const onToggledTagsChanged = async (tagsToggled: string[]) => {
  if (tagsToggled.length < 1) {
    Object.keys(entries.value).forEach(async entryId => {
      (await entries.value[entryId]).isHidden = false
    })
  } else {
    Object.keys(entries.value).forEach(async entryId => {
      (await entries.value[entryId]).isHidden = !(await entries.value[entryId]).tags?.some(own => tagsToggled.includes(own))
    })
  }
}

/**
 * Handler for the toggle for hiding/showing warnings;
 * updates localstorage with the state of the checkbox
 * so that it is saved between page loads
 * @param event the event context which invoked this handler
 */
const onHideWarningsToggled = (event: Event) => {
  storage.write(`${storageId}::hideWarnings`, (event.target as HTMLInputElement).checked)
}

onMounted(async () => {
  let listConfig = await fetchAndParseConfig<MediaList>(routeConfig.config)
  const list = await fetchConfigsFromList<MediaEntry>(listConfig)
  config.value = listConfig
  entries.value = list.entries
  document.title = routeConfig.fullTitle
  ready.value = true
  hasWarnings.value = !!(await Promise.all(Object.values(list.entries))).find(other => !!other.warnings)
})
</script>

<template lang="pug">
.template(
  :class='[template]'
)
  Transition
    .navigation(
      v-if='ready'
    )
      .input.labeled-checkbox(
        v-if='hasWarnings && !config.removeHideWarningsToggle'
      )
        label(
          for='warning-toggle-checkbox'
        ) Hide Warnings
        input(
          type='checkbox'
          name='warning-toggle-checkbox'
          id='warning-toggle-checkbox'
          v-model='hideWarnings'
          @input='onHideWarningsToggled($event)'
        )
  Transition
    FilterPanel(
      v-if='ready && !!config.tags'
      :tags='config.tags'
      @toggledTagsChanged='onToggledTagsChanged($event)'
    )
  Transition
    div(
      v-if='ready'
      :class='[className]'
    )
      Transition(
        v-for='(entry, id) in entries'
      )
        GalleryTile(
          v-if='template === "gallery-list" && (!entry.isHidden || !config.removeFromView)'
          :class='{ hidden: entry.isHidden && !config.removeFromView }'
          :hideWarnings='hideWarnings'
          :id='id'
          :viewPath='viewPath'
          :isInternal='true'
          :entry='entry'
        )
        ArticleTile(
          v-else-if='template === "article-list" && (!entry.isHidden || !config.removeFromView)'
          :class='{ hidden: entry.isHidden && !config.removeFromView }'
          :hideWarnings='hideWarnings'
          :id='id'
          :viewPath='viewPath'
          :isInternal='true'
          :entry='entry'
        )
</template>
