<script setup lang="ts">
import type { BackendError, SettingsGroup, SettingsDataEntry, FunctionRef, Form } from '~/types'
import axios from 'axios'
import SignupFormBuilder from '~/components/admin/SignupFormBuilder.vue'
import useFormData from '~/composables/useFormData'
import { ref, computed, reactive } from 'vue'
import { useStore } from '~/store'
import useLogger from '~/composables/useLogger'

interface Props {
  group: SettingsGroup
  settingsData: SettingsDataEntry[]
}

const props = defineProps<Props>()

const values = reactive({} as Record<string, unknown | Form | string>)
const result = ref<boolean | null>(null)
const errors = ref([] as string[])

const logger = useLogger()
const store = useStore()

// TODO (wvffle): Use VueUse
const fileRefs = reactive({} as Record<string, HTMLInputElement>)
const setFileRef = (identifier: string) => (el: FunctionRef) => {
  logger.debug(el)
  fileRefs[identifier] = el as HTMLInputElement
}

const settings = computed(() => {
  const byIdentifier = props.settingsData.reduce((acc, entry) => {
    acc[entry.identifier] = entry
    return acc
  }, {} as Record<string, SettingsDataEntry>)

  return props.group.settings.map(entry => {
    return { ...byIdentifier[entry.name], fieldType: entry.fieldType, fieldParams: entry.fieldParams || {} }
  })
})

const fileSettings = computed(() => settings.value.filter(setting => setting.field.widget.class === 'ImageWidget'))

for (const setting of settings.value) {
  values[setting.identifier] = setting.value
}

const isLoading = ref(false)
const save = async () => {
  errors.value = []
  result.value = null

  let postData: unknown = values
  let contentType = 'application/json'

  if (fileSettings.value.length > 0) {
    const fileSettingsIDs = fileSettings.value.map((setting) => setting.identifier)
    const data = settings.value.reduce((data, setting) => {
      if (fileSettingsIDs.includes(setting.identifier)) {
        const input = fileRefs[setting.identifier]
        const { files } = input

        logger.debug('ref', input, files)

        if (files && files.length > 0) {
          data[setting.identifier] = files[0]
        }
      } else {
        data[setting.identifier] = values[setting.identifier] as string
      }

      return data
    }, {} as Record<string, string | File>)

    contentType = 'multipart/form-data'
    postData = useFormData(data)
  }

  try {
    const response = await axios.post('instance/admin/settings/bulk/', postData, {
      headers: { 'Content-Type': contentType }
    })

    result.value = true
    for (const setting of response.data) {
      values[setting.identifier] = setting.value
    }

    await store.dispatch('instance/fetchSettings')
  } catch (error) {
    errors.value = (error as BackendError).backendErrors
  }

  isLoading.value = false
}
</script>

<template>
  <form
    :id="group.id"
    class="ui form component-settings-group"
    @submit.prevent="save"
  >
    <div class="ui divider" />
    <h3 class="ui header">
      {{ group.label }}
    </h3>
    <div
      v-if="errors.length > 0"
      role="alert"
      class="ui negative message"
    >
      <h4 class="header">
        {{ $t('components.admin.SettingsGroup.header.error') }}
      </h4>
      <ul class="list">
        <li
          v-for="(error, key) in errors"
          :key="key"
        >
          {{ error }}
        </li>
      </ul>
    </div>
    <div
      v-if="result"
      class="ui positive message"
    >
      {{ $t('components.admin.SettingsGroup.message.success') }}
    </div>
    <div
      v-for="(setting, key) in settings"
      :key="key"
      class="ui field"
    >
      <template v-if="setting.field.widget.class !== 'CheckboxInput'">
        <label :for="setting.identifier">{{ setting.verbose_name }}</label>
        <p v-if="setting.help_text">
          {{ setting.help_text }}
        </p>
      </template>
      <content-form
        v-if="setting.fieldType === 'markdown'"
        v-bind="setting.fieldParams"
        v-model="values[setting.identifier]"
      />
      <!-- eslint-disable vue/valid-v-model -->
      <signup-form-builder
        v-else-if="setting.fieldType === 'formBuilder'"
        v-model="values[setting.identifier] as Form"
        :signup-approval-enabled="!!values.moderation__signup_approval_enabled"
      />
      <!-- eslint-enable vue/valid-v-model -->
      <input
        v-else-if="setting.field.widget.class === 'PasswordInput'"
        :id="setting.identifier"
        v-model="values[setting.identifier]"
        :name="setting.identifier"
        type="password"
        class="ui input"
      >
      <input
        v-else-if="setting.field.widget.class === 'TextInput'"
        :id="setting.identifier"
        v-model="values[setting.identifier]"
        :name="setting.identifier"
        type="text"
        class="ui input"
      >
      <input
        v-else-if="setting.field.class === 'IntegerField'"
        :id="setting.identifier"
        v-model.number="values[setting.identifier]"
        :name="setting.identifier"
        type="number"
        class="ui input"
      >
      <!-- eslint-disable vue/valid-v-model -->
      <textarea
        v-else-if="setting.field.widget.class === 'Textarea'"
        :id="setting.identifier"
        v-model="values[setting.identifier] as string"
        :name="setting.identifier"
        type="text"
        class="ui input"
      />
      <!-- eslint-enable vue/valid-v-model -->
      <div
        v-else-if="setting.field.widget.class === 'CheckboxInput'"
        class="ui toggle checkbox"
      >
        <!-- eslint-disable vue/valid-v-model -->
        <input
          :id="setting.identifier"
          v-model="values[setting.identifier] as boolean"
          :name="setting.identifier"
          type="checkbox"
        >
        <!-- eslint-enable vue/valid-v-model -->
        <label :for="setting.identifier">{{ setting.verbose_name }}</label>
        <p v-if="setting.help_text">
          {{ setting.help_text }}
        </p>
      </div>
      <select
        v-else-if="setting.field.class === 'MultipleChoiceField'"
        :id="setting.identifier"
        v-model="values[setting.identifier]"
        multiple
        class="ui search selection dropdown"
      >
        <option
          v-for="v in setting.additional_data?.choices"
          :key="v[0]"
          :value="v[0]"
        >
          {{ v[1] }}
        </option>
      </select>
      <div v-else-if="setting.field.widget.class === 'ImageWidget'">
        <input
          :id="setting.identifier"
          :ref="setFileRef(setting.identifier)"
          type="file"
        >
        <div v-if="values[setting.identifier]">
          <div class="ui hidden divider" />
          <h3 class="ui header">
            {{ $t('components.admin.SettingsGroup.header.image') }}
          </h3>
          <img
            v-if="values[setting.identifier]"
            class="ui image"
            alt=""
            :src="$store.getters['instance/absoluteUrl'](values[setting.identifier])"
          >
        </div>
      </div>
    </div>
    <button
      type="submit"
      :class="['ui', {'loading': isLoading}, 'right', 'floated', 'success', 'button']"
    >
      {{ $t('components.admin.SettingsGroup.button.save') }}
    </button>
  </form>
</template>
