<script setup lang="ts">
import { computed, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n'

import api from '@/api'
import { APIBadRequestError } from '@/api/errors'
import { useForm } from '@/composables/form'
import { useAutoModal } from '@/composables/useAutoModal'
import { asUnreffed } from '@/helpers/commons'
import {
  alphalownumdot_,
  minLength,
  name,
  required,
  sameAs,
} from '@/helpers/validators'
import { formatForm } from '@/helpers/yunohostArguments'
import type { FieldProps, FormFieldDict } from '@/types/form'
import LoginView from '@/views/LoginView.vue'
import { DomainForm } from '@/views/_partials'

const { t } = useI18n()
const modalConfirm = useAutoModal()

type Steps = 'start' | 'domain' | 'user' | 'rootfsspace-error' | 'login'
const step = ref<Steps>('start')
const serverError = ref('')
const domain = ref('')
const dyndns_recovery_password = ref('')

type Form = typeof form.value
const form = ref({
  username: '',
  fullname: '',
  password: '',
  confirmation: '',
})
const fields = reactive({
  // FIXME satisfies FormFieldDict but not for CardForm?
  alert: {
    component: 'ReadOnlyAlertItem',
    props: { label: t('postinstall.user.first_user_help'), type: 'info' },
  } satisfies FieldProps<'ReadOnlyAlertItem'>,

  username: {
    component: 'InputItem',
    label: t('user_username'),
    rules: { required, alphalownumdot_ },
    props: { id: 'username', placeholder: t('placeholder.username') },
  } satisfies FieldProps<'InputItem', Form['username']>,

  fullname: {
    component: 'InputItem',
    label: t('user_fullname'),
    rules: { required, name },
    props: { id: 'fullname', placeholder: t('placeholder.fullname') },
  } satisfies FieldProps<'InputItem', Form['fullname']>,

  password: {
    component: 'InputItem',
    label: t('password'),
    description: t('good_practices_about_admin_password'),
    descriptionVariant: 'warning',
    rules: { required, passwordLenght: minLength(8) },
    props: { id: 'password', placeholder: '••••••••', type: 'password' },
  } satisfies FieldProps<'InputItem', Form['password']>,

  confirmation: {
    component: 'InputItem',
    label: t('password_confirmation'),
    rules: asUnreffed(
      computed(() => ({
        required,
        passwordMatch: sameAs(form.value.password),
      })),
    ),
    props: { id: 'confirmation', placeholder: '••••••••', type: 'password' },
  } satisfies FieldProps<'InputItem', Form['confirmation']>,
} satisfies FormFieldDict<Form>)

const { v, onSubmit, serverErrors } = useForm(form, fields)

function goToStep(step_: Steps) {
  serverError.value = ''
  step.value = step_
}

function setDomain(data: { domain: string; dyndns_recovery_password: string }) {
  domain.value = data.domain
  dyndns_recovery_password.value = data.dyndns_recovery_password
  goToStep('user')
}

const setUser = onSubmit(async () => {
  const confirmed = await modalConfirm(
    t('confirm_postinstall', { domain: domain.value }),
  )
  if (!confirmed) return
  performPostInstall()
})

async function performPostInstall(force = false) {
  const { username, fullname, password } = form.value
  const data = await formatForm(
    {
      domain: domain.value,
      dyndns_recovery_password: dyndns_recovery_password.value,
      username,
      fullname,
      password,
    },
    { removeEmpty: true },
  )

  // FIXME does the api will throw an error for bad passwords ?
  api
    .post('postinstall' + (force ? '?force_diskspace' : ''), data, {
      key: 'postinstall',
    })
    .then(() => {
      // Display success message and allow the user to login
      goToStep('login')
    })
    .catch((err) => {
      const hasWordsInError = (words: string[]) =>
        words.some((word) => (err.key || err.message).includes(word))
      if (!(err instanceof APIBadRequestError)) throw err
      if (err.key === 'postinstall_low_rootfsspace') {
        step.value = 'rootfsspace-error'
        serverError.value = err.message
      } else if (hasWordsInError(['domain', 'dyndns'])) {
        step.value = 'domain'
        serverError.value = err.message
      } else if (hasWordsInError(['password', 'user'])) {
        step.value = 'user'
        serverErrors.global = [err.message]
      } else {
        throw err
      }
    })
}
</script>

<template>
  <div class="post-install">
    <!-- START STEP -->
    <template v-if="step === 'start'">
      <p class="alert alert-success">
        <YIcon iname="thumbs-up" /> {{ $t('postinstall_intro_1') }}
      </p>

      <p class="alert alert-info">
        <span v-t="'postinstall_intro_2'" />
        <br />
        <span v-html="$t('postinstall_intro_3')" />
      </p>

      <BButton size="lg" variant="success" @click="goToStep('domain')">
        {{ $t('begin') }}
      </BButton>
    </template>

    <!-- DOMAIN SETUP STEP -->
    <template v-else-if="step === 'domain'">
      <DomainForm
        :title="$t('postinstall_set_domain')"
        :submit-text="$t('next')"
        :server-error="serverError"
        @submit="setDomain"
      >
        <template #disclaimer>
          <p v-t="'postinstall_domain'" class="alert alert-info" />
        </template>
      </DomainForm>

      <BButton variant="primary" class="mt-3" @click="goToStep('start')">
        <YIcon iname="chevron-left" /> {{ $t('previous') }}
      </BButton>
    </template>

    <!-- FIRST USER SETUP STEP -->
    <template v-else-if="step === 'user'">
      <CardForm
        v-model="form"
        :fields="fields"
        icon="user-plus"
        :submit-text="$t('next')"
        :title="$t('postinstall.user.title')"
        :validations="v"
        @submit.prevent="setUser"
      />

      <BButton variant="primary" class="mt-3" @click="goToStep('domain')">
        <YIcon iname="chevron-left" /> {{ $t('previous') }}
      </BButton>
    </template>

    <template v-else-if="step === 'rootfsspace-error'">
      <YCard no-body header-class="d-none" footer-bg-variant="danger">
        <BCardBody class="alert alert-danger m-0">
          {{ serverError }}
        </BCardBody>

        <template #buttons>
          <BButton variant="light" size="sm" @click="performPostInstall(true)">
            <YIcon iname="warning" /> {{ $t('postinstall.force') }}
          </BButton>
        </template>
      </YCard>
    </template>

    <!-- POST-INSTALL SUCCESS STEP -->
    <template v-else-if="step === 'login'">
      <p class="alert alert-success">
        <YIcon iname="thumbs-up" /> {{ $t('installation_complete') }}
      </p>
      <LoginView />
    </template>
  </div>
</template>
