<script setup lang="ts">
import type { ContentCategory, Channel, BackendError } from '~/types'

import { slugify } from 'transliteration'
import { reactive, computed, ref, watchEffect, watch } from 'vue'
import { useGettext } from 'vue3-gettext'

import axios from 'axios'
import AttachmentInput from '~/components/common/AttachmentInput.vue'
import TagsSelector from '~/components/library/TagsSelector.vue'

interface Events {
  (e: 'category', contentCategory: ContentCategory): void
  (e: 'submittable', value: boolean): void
  (e: 'loading', value: boolean): void
  (e: 'errored', errors: string[]): void
  (e: 'created', channel: Channel): void
  (e: 'updated', channel: Channel): void
}

interface Props {
  object?: Channel | null
  step: number
}

const emit = defineEmits<Events>()
const props = withDefaults(defineProps<Props>(), {
  object: null,
  step: 1
})

const { $pgettext } = useGettext()

const newValues = reactive({
  name: props.object?.artist?.name ?? '',
  username: props.object?.actor.preferred_username ?? '',
  tags: props.object?.artist?.tags ?? [] as string[],
  description: props.object?.artist?.description?.text ?? '',
  cover: props.object?.artist?.cover?.uuid ?? null,
  content_category: props.object?.artist?.content_category ?? 'podcast',
  metadata: { ...(props.object?.metadata ?? {}) }
})

const creating = computed(() => props.object === null)
const categoryChoices = computed(() => [
  {
    value: 'podcast',
    label: $pgettext('*/*/*', 'Podcasts'),
    helpText: $pgettext('Content/Channels/Help', 'Host your episodes and keep your community updated.')
  },
  {
    value: 'music',
    label: $pgettext('*/*/*', 'Artist discography'),
    helpText: $pgettext('Content/Channels/Help', 'Publish music you make as a nice discography of albums and singles.')
  }
])

interface ITunesCategory {
  value: string
  label: string
  children: []
}

interface MetadataChoices {
  itunes_category?: ITunesCategory[] | null
  language: {
    value: string
    label: string
  }[]
}

const metadataChoices = ref({ itunes_category: null } as MetadataChoices)
const itunesSubcategories = computed(() => {
  for (const element of metadataChoices.value.itunes_category ?? []) {
    if (element.value === newValues.metadata.itunes_category) {
      return element.children ?? []
    }
  }

  return []
})

const labels = computed(() => ({
  namePlaceholder: $pgettext('Content/Channel/Form.Field.Placeholder', 'Awesome channel name'),
  usernamePlaceholder: $pgettext('Content/Channel/Form.Field.Placeholder', 'awesomechannelname')
}))

const submittable = computed(() => !!(
  newValues.content_category === 'podcast'
    ? newValues.name && newValues.username && newValues.metadata.itunes_category && newValues.metadata.language
    : newValues.name && newValues.username
))

watch(() => newValues.name, (name) => {
  if (creating.value) {
    newValues.username = slugify(name)
  }
})

watch(() => newValues.metadata.itunes_category, () => {
  newValues.metadata.itunes_subcategory = null
})

const isLoading = ref(false)
const errors = ref([] as string[])

watchEffect(() => emit('category', newValues.content_category))
watchEffect(() => emit('loading', isLoading.value))
watchEffect(() => emit('submittable', submittable.value))

// TODO (wvffle): Add loader / Use Suspense
const fetchMetadataChoices = async () => {
  try {
    const response = await axios.get('channels/metadata-choices')
    metadataChoices.value = response.data
  } catch (error) {
    errors.value = (error as BackendError).backendErrors
  }
}

fetchMetadataChoices()

const submit = async () => {
  isLoading.value = true

  const payload = {
    ...newValues,
    description: newValues.description
      ? {
          content_type: 'text/markdown',
          text: newValues.description
        }
      : null
  }

  try {
    const request = () => creating.value
      ? axios.post('channels/', payload)
      : axios.patch(`channels/${props.object?.uuid}`, payload)

    const response = await request()
    if (creating.value) emit('created', response.data)
    else emit('updated', response.data)
  } catch (error) {
    errors.value = (error as BackendError).backendErrors
    emit('errored', errors.value)
  }

  isLoading.value = false
}
</script>

<template>
  <form
    class="ui form"
    @submit.prevent.stop="submit"
  >
    <div
      v-if="errors.length > 0"
      role="alert"
      class="ui negative message"
    >
      <h4 class="header">
        <translate translate-context="Content/*/Error message.Title">
          Error while saving channel
        </translate>
      </h4>
      <ul class="list">
        <li
          v-for="(error, key) in errors"
          :key="key"
        >
          {{ error }}
        </li>
      </ul>
    </div>
    <template v-if="metadataChoices">
      <fieldset
        v-if="creating && step === 1"
        class="ui grouped channel-type required field"
      >
        <legend>
          <translate translate-context="Content/Channel/Paragraph">
            What will this channel be used for?
          </translate>
        </legend>
        <div class="ui hidden divider" />
        <div class="field">
          <div
            v-for="(choice, key) in categoryChoices"
            :key="key"
            :class="['ui', 'radio', 'checkbox', {selected: choice.value == newValues.content_category}]"
          >
            <input
              :id="`category-${choice.value}`"
              v-model="newValues.content_category"
              type="radio"
              name="channel-category"
              :value="choice.value"
            >
            <label :for="`category-${choice.value}`">
              <span :class="['right floated', 'placeholder', 'image', {circular: choice.value === 'music'}]" />
              <strong>{{ choice.label }}</strong>
              <div class="ui small hidden divider" />
              {{ choice.helpText }}
            </label>
          </div>
        </div>
      </fieldset>
      <template v-if="!creating || step === 2">
        <div class="ui required field">
          <label for="channel-name">
            <translate translate-context="Content/Channel/*">Name</translate>
          </label>
          <input
            v-model="newValues.name"
            type="text"
            required
            :placeholder="labels.namePlaceholder"
          >
        </div>
        <div class="ui required field">
          <label for="channel-username">
            <translate translate-context="Content/Channel/*">Fediverse handle</translate>
          </label>
          <div class="ui left labeled input">
            <div class="ui basic label">
              @
            </div>
            <input
              v-model="newValues.username"
              type="text"
              :required="creating"
              :disabled="!creating"
              :placeholder="labels.usernamePlaceholder"
            >
          </div>
          <template v-if="creating">
            <div class="ui small hidden divider" />
            <p>
              <translate translate-context="Content/Channels/Paragraph">
                Used in URLs and to follow this channel in the Fediverse. It cannot be changed later.
              </translate>
            </p>
          </template>
        </div>
        <div class="six wide column">
          <attachment-input
            v-model="newValues.cover"
            :image-class="newValues.content_category === 'podcast' ? '' : 'circular'"
            @delete="newValues.cover = null"
          >
            <translate translate-context="Content/Channel/*">
              Channel Picture
            </translate>
          </attachment-input>
        </div>
        <div class="ui small hidden divider" />
        <div class="ui stackable grid row">
          <div class="ten wide column">
            <div class="ui field">
              <label for="channel-tags">
                <translate translate-context="*/*/*">Tags</translate>
              </label>
              <tags-selector
                id="channel-tags"
                v-model="newValues.tags"
                :required="false"
              />
            </div>
          </div>
          <div
            v-if="newValues.content_category === 'podcast'"
            class="six wide column"
          >
            <div class="ui required field">
              <label for="channel-language">
                <translate translate-context="*/*/*">Language</translate>
              </label>
              <select
                id="channel-language"
                v-model="newValues.metadata.language"
                name="channel-language"
                required
                class="ui search selection dropdown"
              >
                <option
                  v-for="(v, key) in metadataChoices.language"
                  :key="key"
                  :value="v.value"
                >
                  {{ v.label }}
                </option>
              </select>
            </div>
          </div>
        </div>
        <div class="ui small hidden divider" />
        <div class="ui field">
          <label for="channel-name">
            <translate translate-context="*/*/*">Description</translate>
          </label>
          <content-form v-model="newValues.description" />
        </div>
        <div
          v-if="newValues.content_category === 'podcast'"
          class="ui two fields"
        >
          <div class="ui required field">
            <label for="channel-itunes-category">
              <translate translate-context="*/*/*">Category</translate>
            </label>
            <select
              id="itunes-category"
              v-model="newValues.metadata.itunes_category"
              name="itunes-category"
              required
              class="ui dropdown"
            >
              <option
                v-for="(v, key) in metadataChoices.itunes_category"
                :key="key"
                :value="v.value"
              >
                {{ v.label }}
              </option>
            </select>
          </div>
          <div class="ui field">
            <label for="channel-itunes-category">
              <translate translate-context="*/*/*">Subcategory</translate>
            </label>
            <select
              id="itunes-category"
              v-model="newValues.metadata.itunes_subcategory"
              name="itunes-category"
              :disabled="!newValues.metadata.itunes_category"
              class="ui dropdown"
            >
              <option
                v-for="(v, key) in itunesSubcategories"
                :key="key"
                :value="v"
              >
                {{ v }}
              </option>
            </select>
          </div>
        </div>
        <div
          v-if="newValues.content_category === 'podcast'"
          class="ui two fields"
        >
          <div class="ui field">
            <label for="channel-itunes-email">
              <translate translate-context="*/*/*">Owner e-mail address</translate>
            </label>
            <input
              id="channel-itunes-email"
              v-model="newValues.metadata.owner_email"
              name="channel-itunes-email"
              type="email"
            >
          </div>
          <div class="ui field">
            <label for="channel-itunes-name">
              <translate translate-context="*/*/*">Owner name</translate>
            </label>
            <input
              id="channel-itunes-name"
              v-model="newValues.metadata.owner_name"
              name="channel-itunes-name"
              maxlength="255"
            >
          </div>
        </div>
        <p>
          <translate translate-context="*/*/*">
            Used for the itunes:email and itunes:name field required by certain platforms such as Spotify or iTunes.
          </translate>
        </p>
      </template>
    </template>
    <div
      v-else
      class="ui active inverted dimmer"
    >
      <div class="ui text loader">
        <translate translate-context="*/*/*">
          Loading
        </translate>
      </div>
    </div>
  </form>
</template>
