<script setup lang="ts">
import { Label, PinInputInput, PinInputRoot } from 'radix-vue'
import { object, string, type InferType } from 'yup'
import type { FormSubmitEvent } from '#ui/types'
import { useFetchWrapped } from '~/composables/useFetchWrapped'

const emit = defineEmits(['close'])
const toast = useToast()
const overlay = useOverlay()
const loginState = useLoginState()

const sms_triggered = ref(false)
const sms_sending = ref(false)
const sms_counting_down = ref(0)
const final_loading = ref(false)

const items = [
  {
    key: 'sms',
    label: '短信登录',
    icon: 'i-tabler-message-2',
    description: '使用短信验证码登录，未注册的账号将自动注册',
  },
  {
    key: 'account',
    label: '密码登录',
    icon: 'i-tabler-key',
    description: '使用已有账号和密码登录',
  },
  {
    key: 'recovery',
    label: '找回密码',
    icon: 'i-tabler-lock',
    description: '忘记密码时，可以通过手机号和验证码重置密码',
  },
]

const currentTab = ref(0)

const accountForm = reactive<req.user.Login>({ username: '', password: '' })
const smsForm = reactive({ mobile: '', sms_code: [] })

function onSubmit(form: req.user.Login) {
  console.log('Submitted form:', form)
  final_loading.value = true
  useFetchWrapped<req.user.Login, BaseResponse<resp.user.Login>>(
    'App.User_User.Login',
    {
      username: form.username,
      password: form.password,
    }
  )
    .then((res) => {
      final_loading.value = false
      if (res.ret !== 200) {
        toast.add({
          title: '登录失败',
          description: res.msg || '未知错误',
          color: 'error',
          icon: 'i-tabler-circle-x',
        })
        return
      }
      if (!res.data.is_login) {
        toast.add({
          title: '登录失败',
          description: res.msg || '账号或密码错误',
          color: 'error',
          icon: 'i-tabler-circle-x',
        })
        return
      }
      if (!res.data.token || !res.data.user_id) {
        toast.add({
          title: '登录失败',
          description: res.msg || '无法获取登录状态',
          color: 'error',
          icon: 'i-tabler-circle-x',
        })
        return
      }
      loginState.token = res.data.token
      loginState.user.id = res.data.user_id
      loginState
        .updateProfile()
        .then(() => {
          loginState.checkSession()
          // TODO: only close the specific modal
          overlay.closeAll()
          toast.add({
            title: '登录成功',
            description: `${loginState.user.username}, 欢迎回来`,
            color: 'primary',
            icon: 'i-tabler-login-2',
          })
        })
        .catch((err) => {
          toast.add({
            title: '登录失败',
            description: err.msg || '网络错误',
            color: 'error',
            icon: 'i-tabler-circle-x',
          })
        })
        .finally(() => {
          final_loading.value = false
        })
    })
    .catch((err) => {
      toast.add({
        title: '登录失败',
        description: err.msg || '网络错误',
        color: 'error',
        icon: 'i-tabler-circle-x',
      })
    })
}

const obtainSmsCode = () => {
  smsForm.sms_code = []
  sms_sending.value = true

  useFetchWrapped<req.user.SmsLogin, BaseResponse<resp.user.SmsLogin>>(
    'App.User_User.MobileLogin',
    {
      mobile: smsForm.mobile,
    }
  )
    .then((res) => {
      if (res.ret !== 200) {
        sms_sending.value = false
        toast.add({
          title: '验证码发送失败',
          description: res.msg || '未知错误',
          color: 'error',
          icon: 'i-tabler-circle-x',
        })
        return
      }
      sms_triggered.value = true
      sms_sending.value = false
      sms_counting_down.value = 60 // TODO: save timestamp to localstorage
      toast.add({
        title: '短信验证码已发送',
        color: 'primary',
        icon: 'i-tabler-circle-check',
      })
      const interval = setInterval(() => {
        sms_counting_down.value--
        if (sms_counting_down.value <= 0) {
          clearInterval(interval)
        }
      }, 1000)
    })
    .catch((err) => {
      toast.add({
        title: '验证码发送失败',
        description: err.msg || '网络错误',
        color: 'error',
        icon: 'i-tabler-circle-x',
      })
    })
}

const handle_sms_verify = (e: string[]) => {
  final_loading.value = true
  useFetchWrapped<
    req.user.SmsLoginVerify,
    BaseResponse<resp.user.SmsLoginVerify>
  >('App.User_User.MobileLoginVerify', {
    mobile: smsForm.mobile,
    sms_code: e.join(''),
  })
    .then((res) => {
      if (res.ret !== 200) {
        smsForm.sms_code = []
        toast.add({
          title: '登录失败',
          description: res.msg || '未知错误',
          color: 'error',
          icon: 'i-tabler-circle-x',
        })
        return
      }
      if (!res.data.token || !res.data.person_id) {
        smsForm.sms_code = []
        toast.add({
          title: '登录失败',
          description: res.msg || '无法获取登录状态',
          color: 'error',
          icon: 'i-tabler-circle-x',
        })
        return
      }
      loginState.token = res.data.token
      loginState.user.id = res.data.person_id
      loginState
        .updateProfile()
        .then(() => {
          loginState.checkSession()
          emit('close')
          toast.add({
            title: '登录成功',
            description: `${loginState.user.username}, 欢迎回来`,
            color: 'primary',
            icon: 'i-tabler-login-2',
          })
        })
        .catch((err) => {
          toast.add({
            title: '登录失败',
            description: err.msg || '网络错误',
            color: 'error',
            icon: 'i-tabler-circle-x',
          })
        })
        .finally(() => {
          final_loading.value = false
        })
    })
    .finally(() => (final_loading.value = false))
}

const forgetPasswordState = reactive({
  mobile: '',
  sms_code: '',
  password: '',
})

const forgetPasswordSchema = object({
  mobile: string()
    .required('请输入手机号')
    .matches(/^1[3-9]\d{9}$/, '手机号格式不正确'),
  sms_code: string().required('请输入验证码').length(4, '验证码长度为4位'),
  password: string().required('请输入新密码').min(6, '密码长度至少为6位'),
})

type ForgetPasswordSchema = InferType<typeof forgetPasswordSchema>

const obtainForgetSmsCode = () => {
  forgetPasswordState.sms_code = ''
  sms_sending.value = true

  useFetchWrapped<req.user.SmsChangePasswordVerify, BaseResponse<{}>>(
    'App.User_User.ForgotPasswordSms',
    {
      mobile: forgetPasswordState.mobile,
    }
  )
    .then((res) => {
      if (res.ret !== 200) {
        sms_sending.value = false
        toast.add({
          title: '验证码发送失败',
          description: res.msg || '未知错误',
          color: 'error',
          icon: 'i-tabler-circle-x',
        })
        return
      }
      sms_triggered.value = true
      sms_sending.value = false
      sms_counting_down.value = 60 // TODO: save timestamp to localstorage
      toast.add({
        title: '短信验证码已发送',
        color: 'primary',
        icon: 'i-tabler-circle-check',
      })
      const interval = setInterval(() => {
        sms_counting_down.value--
        if (sms_counting_down.value <= 0) {
          clearInterval(interval)
        }
      }, 1000)
    })
    .catch((err) => {
      toast.add({
        title: '验证码发送失败',
        description: err.msg || '网络错误',
        color: 'error',
        icon: 'i-tabler-circle-x',
      })
    })
}

const onForgetPasswordSubmit = (
  event: FormSubmitEvent<ForgetPasswordSchema>
) => {
  final_loading.value = true
  useFetchWrapped<req.user.SmsChangePassword, BaseResponse<{}>>(
    'App.User_User.ForgotPassword',
    {
      mobile: event.data.mobile,
      sms_code: event.data.sms_code,
      new_password: event.data.password,
    }
  )
    .then((res) => {
      final_loading.value = false
      if (res.ret !== 200) {
        toast.add({
          title: '重置密码失败',
          description: res.msg || '未知错误',
          color: 'error',
          icon: 'i-tabler-circle-x',
        })
        return
      }
      toast.add({
        title: '重置密码成功',
        description: '请您继续登录',
        color: 'success',
        icon: 'i-tabler-circle-check',
      })
      currentTab.value = 1
    })
    .catch((err) => {
      toast.add({
        title: '重置密码失败',
        description: err.msg || '未知错误',
        color: 'error',
        icon: 'i-tabler-circle-x',
      })
    })
}
</script>

<template>
  <UModal :dismissible="false">
    <template #content>
      <UCard>
        <template #header>
          <div class="flex items-center justify-between">
            <h3
              class="text-base font-semibold leading-6 text-gray-900 dark:text-white"
            >
              登录眩生花 AI 助手
            </h3>
            <UButton
              color="neutral"
              variant="ghost"
              icon="i-heroicons-x-mark-20-solid"
              class="-my-1"
              @click="$emit('close')"
            />
          </div>
        </template>

        <UTabs
          :items="items"
          class="w-full"
          v-model="currentTab"
        >
          <!-- <template #default="{ item, index, selected }">
            <div class="relative flex items-center gap-2 truncate">
              <span class="truncate">{{ item.label }}</span>
              <span
                v-if="selected"
                class="bg-primary-500 dark:bg-primary-400 absolute -right-4 h-2 w-2 rounded-full"
              />
            </div>
          </template> -->
          <template #content="{ item }">
            <UCard @submit.prevent="() => onSubmit(accountForm)">
              <template #header>
                <p
                  class="text-base font-semibold leading-6 text-gray-900 dark:text-white"
                >
                  {{ item.label }}
                </p>
                <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
                  {{ item.description }}
                </p>
              </template>

              <div
                v-if="item.key === 'account'"
                class="space-y-3"
              >
                <UFormField
                  label="用户名"
                  name="username"
                  required
                >
                  <UInput
                    v-model="accountForm.username"
                    :disabled="final_loading"
                    required
                  />
                </UFormField>
                <UFormField
                  label="密码"
                  name="password"
                  required
                >
                  <UInput
                    v-model="accountForm.password"
                    :disabled="final_loading"
                    type="password"
                    required
                  />
                </UFormField>
              </div>

              <div
                v-else-if="item.key === 'sms'"
                class="space-y-3"
              >
                <UFormField
                  label="手机号"
                  name="mobile"
                  required
                >
                  <UButtonGroup class="w-full">
                    <UInput
                      v-model="smsForm.mobile"
                      :disabled="final_loading"
                      type="sms"
                      class="w-full"
                      required
                    >
                      <template #leading>
                        <span class="text-xs text-gray-500 dark:text-gray-400">
                          +86
                        </span>
                      </template>
                    </UInput>
                    <UButton
                      :label="
                        sms_counting_down
                          ? `${sms_counting_down}秒后重发`
                          : '获取验证码'
                      "
                      @click="obtainSmsCode"
                      :loading="sms_sending"
                      :disabled="!!sms_counting_down || final_loading"
                      class="text-xs font-bold"
                      color="neutral"
                    />
                  </UButtonGroup>
                </UFormField>
                <Transition name="pin-root">
                  <div v-if="sms_triggered">
                    <Label
                      for="pin-input"
                      class="pin-label"
                    >
                      验证码
                    </Label>
                    <PinInputRoot
                      id="sms-input"
                      v-model="smsForm.sms_code"
                      :disabled="sms_sending || final_loading"
                      placeholder="○"
                      class="mt-1 flex w-full items-center justify-between gap-2 md:justify-start"
                      @complete="handle_sms_verify"
                      type="number"
                      otp
                      required
                    >
                      <PinInputInput
                        v-for="(id, index) in 4"
                        :key="id"
                        :index="index"
                        class="pin-input"
                        :autofocus="index === 0"
                      />
                    </PinInputRoot>
                  </div>
                </Transition>
              </div>

              <div
                v-if="item.key === 'recovery'"
                class="space-y-3"
              >
                <UForm
                  class="space-y-3"
                  :schema="forgetPasswordSchema"
                  :state="forgetPasswordState"
                  @submit="onForgetPasswordSubmit"
                >
                  <UFormField
                    label="手机号"
                    name="mobile"
                    required
                  >
                    <UButtonGroup class="w-full">
                      <UInput
                        v-model="forgetPasswordState.mobile"
                        :disabled="final_loading"
                        type="tel"
                        class="w-full"
                      >
                        <template #leading>
                          <span
                            class="text-xs text-gray-500 dark:text-gray-400"
                          >
                            +86
                          </span>
                        </template>
                      </UInput>
                      <UButton
                        :label="
                          sms_counting_down
                            ? `${sms_counting_down}秒后重发`
                            : '获取验证码'
                        "
                        @click="obtainForgetSmsCode"
                        :loading="sms_sending"
                        :disabled="!!sms_counting_down"
                        class="text-xs font-bold"
                        color="neutral"
                      />
                    </UButtonGroup>
                  </UFormField>
                  <UFormField
                    label="验证码"
                    name="sms_code"
                    required
                  >
                    <UInput
                      v-model="forgetPasswordState.sms_code"
                      type="sms"
                      class="w-full"
                      :disabled="final_loading"
                    />
                  </UFormField>
                  <UFormField
                    label="新密码"
                    name="password"
                    required
                  >
                    <UInput
                      v-model="forgetPasswordState.password"
                      type="password"
                      :disabled="final_loading"
                    />
                  </UFormField>

                  <div>
                    <UButton
                      type="submit"
                      :loading="final_loading"
                    >
                      重置密码
                    </UButton>
                  </div>
                </UForm>
              </div>

              <template
                #footer
                v-if="item.key === 'account'"
              >
                <div class="flex items-center justify-between">
                  <UButton
                    type="submit"
                    color="primary"
                    :loading="final_loading"
                  >
                    登录
                  </UButton>
                  <UButton
                    variant="link"
                    color="neutral"
                    @click="currentTab = 2"
                  >
                    忘记密码
                  </UButton>
                </div>
              </template>
            </UCard>
          </template>
        </UTabs>
      </UCard>
    </template>
  </UModal>
</template>

<style scoped>
@reference '@/assets/css/main.css';

.pin-root-enter-active,
.pin-root-leave-active {
  @apply transition duration-500;
}

.pin-root-enter-from,
.pin-root-leave-to {
  @apply -translate-y-2 opacity-0;
}

.pin-input {
  @apply aspect-square w-full rounded text-center caret-transparent shadow md:w-16;
  @apply focus:ring-3 font-bold outline-0 ring-indigo-500;
}

.pin-label {
  @apply block text-sm font-medium text-gray-700 after:ms-0.5 after:text-red-500 after:content-['*'] dark:text-gray-200 dark:after:text-red-400;
}
</style>
