<script setup lang="ts">
import { CountdownInst, FormInst, FormItemRule, FormRules } from 'naive-ui'
import isMobilePhone from 'validator/es/lib/isMobilePhone'
import { computed, onMounted, ref, shallowReadonly, useTemplateRef, watchEffect } from 'vue'
import { useI18n } from 'vue-i18n'
import SparkMD5 from 'spark-md5'
import { Down, Mail, Lock, Phone } from '@icon-park/vue-next'
import isEmail from 'validator/es/lib/isEmail'
import { useRoute, useRouter } from 'vue-router'
import 'vant/es/dialog/style'
import { ss } from '@/utils/storage'
import { fetchEmailCode, fetchLogin, fetchSMSCode } from '@/apis/user'
import { useUserStore } from '@/store/modules/user'
import { UserInfo } from '@/store/types/user'
import { useSystemLanguageStore } from '@/store/modules/system-language'

type LoginMethod = 'password' | 'sms' | 'email'

enum StorageKeyEnum {
  smsCountdownTime = 'SMS_COUNTDOWN_TIME',
  emailCountdownTime = 'MAIL_COUNTDOWN_TIME',
}

interface LoginPayload {
  loginChannel: 'MEMBER_PLATFOMR_SMS' | 'MEMBER_PLATFOMR_EMAIL' | 'MEMBER_PLATFOMR_PW'
  account: string
  password?: string
  authCode?: string
}

const { t } = useI18n()

const systemLanguageStore = useSystemLanguageStore()
const userStore = useUserStore()
const router = useRouter()
const route = useRoute()

const currentLoginMethod = ref<LoginMethod>('sms')

const currentPhoneNumberArea = ref<'+86' | '+852'>('+86')

const loginBtnLoading = ref(false)

const passwordLoginFormRef = useTemplateRef<FormInst>('passwordLoginFormRef')
const smsLoginFormRef = useTemplateRef<FormInst>('smsLoginFormRef')
const emailLoginFormRef = useTemplateRef<FormInst>('emailLoginFormRef')
const countdownRef = useTemplateRef<CountdownInst>('countdownRef')

const passwordLoginForm = ref({
  account: '',
  password: '',
})

const smsLoginForm = ref({
  phoneNumber: '',
  code: '',
})

const emailLoginForm = ref({
  email: '',
  code: '',
})

const isAgreeTerms = ref(false)

const countdownActive = ref(true)
const isShowCountdown = ref(false)
const countdownDuration = ref<number>(60000)

const showAgreeTermsDialog = ref(false)

const userAgreementUrl = ref('https://tcn9nhw8kfwe.feishu.cn/wiki/Y1ELwRVESi9jw9kshc0chT2ZnSf?fromScene=spaceOverview')
const privacyPolicyUrl = ref('https://tcn9nhw8kfwe.feishu.cn/wiki/OBzxwhGBviHP8lk9ca0chUh9nCc?fromScene=spaceOverview')

const passwordLoginFormRules = shallowReadonly<FormRules>({
  account: { required: true, message: t('login_module.please_enter_your_account_number'), trigger: 'blur' },
  password: { required: true, message: t('login_module.please_enter_your_password'), trigger: 'blur' },
})

const smsLoginFormRules = shallowReadonly<FormRules>({
  phoneNumber: {
    key: 'phoneNumber',
    required: true,
    validator: (_rule: FormItemRule, value: string) => {
      if (!value) {
        return new Error(t('login_module.please_enter_your_cell_phone_number'))
      } else if (!isMobilePhone(value, ['zh-CN', 'zh-HK'])) {
        return new Error(t('login_module.please_enter_your_correct_cell_phone_number'))
      }

      return
    },
    trigger: 'blur',
  },
  code: { required: true, message: t('login_module.please_enter_the_verification_code'), trigger: 'blur' },
})

const emailLoginFormRules = shallowReadonly<FormRules>({
  email: {
    key: 'email',
    required: true,
    validator: (_rule: FormItemRule, value: string) => {
      if (!value) {
        return new Error(t('login_module.please_enter_your_email_address'))
      } else if (!isEmail(value)) {
        return new Error(t('login_module.please_enter_the_correct_email_address'))
      }

      return
    },
    trigger: 'blur',
  },
  code: { required: true, message: t('login_module.please_enter_the_verification_code'), trigger: 'blur' },
})

onMounted(() => {
  document.title = t('common_module.login')
})

const phoneNumberAreaOptions = computed(() => {
  return [
    {
      label: `+86⠀${t('login_module.mainland_china')}`,
      value: '+86',
    },
    {
      label: `+852 ${t('login_module.hong_kong_china')}`,
      value: '+852',
    },
  ]
})

const currentLoginMethodValue = computed(() => {
  switch (currentLoginMethod.value) {
    case 'password':
      return t('login_module.password_login')
    case 'sms':
      return t('login_module.verification_code_login')
    case 'email':
      return t('login_module.email_login')
    default:
      return ''
  }
})

const isEnglishLanguage = computed(() => {
  return systemLanguageStore.currentLanguage === 'en'
})

const agreementPrefix = computed(() => {
  return isEnglishLanguage.value ? '<' : '《'
})

const agreementSuffix = computed(() => {
  return isEnglishLanguage.value ? '>' : '》'
})

watchEffect(() => {
  let timeStringDraft = ''

  switch (currentLoginMethod.value) {
    case 'sms':
      {
        timeStringDraft = ss.get(StorageKeyEnum.smsCountdownTime)
      }
      break
    case 'email':
      {
        timeStringDraft = ss.get(StorageKeyEnum.emailCountdownTime)
      }
      break
  }

  if (timeStringDraft) {
    const time = Math.floor(Date.now() - parseInt(timeStringDraft))

    if (time < 60000) {
      countdownDuration.value = 60000 - time
      countdownRef.value?.reset()
      isShowCountdown.value = true
    }
  }
})

function onlyAllowNumber(value: string) {
  return !value || /^\d+$/.test(value)
}

function noSideSpace(value: string) {
  return !value.startsWith(' ') && !value.endsWith(' ')
}

function countdownRender({ seconds, minutes }: { seconds: number; minutes: number }) {
  if (minutes && minutes === 1) {
    return '60 s'
  }

  return `${seconds} s`
}

function onCountdownFinish() {
  isShowCountdown.value = false
}

// 获取手机验证码
function handleSMSCodeGain() {
  smsLoginFormRef.value?.validate(
    (errors) => {
      if (errors) return ''

      countdownDuration.value = 60000
      ss.set(StorageKeyEnum.smsCountdownTime, Date.now())
      countdownRef.value?.reset()
      isShowCountdown.value = true

      fetchSMSCode(getInputPhoneNumber()).then((res) => {
        if (res.code !== 0) return ''

        window.$message.success(t('login_module.successful'))
      })
    },
    (rule) => {
      return rule.key === 'phoneNumber'
    },
  )
}

// 获取邮箱验证码
function handleEmailCodeGain() {
  emailLoginFormRef.value?.validate(
    (errors) => {
      if (errors) return ''

      countdownDuration.value = 60000
      ss.set(StorageKeyEnum.emailCountdownTime, Date.now())
      countdownRef.value?.reset()
      isShowCountdown.value = true

      fetchEmailCode(encodeURIComponent(emailLoginForm.value.email)).then((res) => {
        if (res.code !== 0) return ''

        window.$message.success(t('login_module.successful'))
      })
    },
    (rule) => {
      return rule.key === 'email'
    },
  )
}

// 获取输入的手机号码
function getInputPhoneNumber() {
  return currentPhoneNumberArea.value !== '+86'
    ? encodeURIComponent(`${currentPhoneNumberArea.value}${smsLoginForm.value.phoneNumber}`)
    : smsLoginForm.value.phoneNumber
}

// 忘记密码
function handleToResetPassword() {
  const redirectUrl = decodeURIComponent((route.query.redirect as string) || '')

  router.replace({
    path: '/reset-password',
    query: redirectUrl ? { redirect: encodeURIComponent(redirectUrl) } : {},
  })
}

// 切换登录方式
function handleLoginMethodChange(method: LoginMethod) {
  currentLoginMethod.value = method
  isAgreeTerms.value = false
  smsLoginForm.value = {
    phoneNumber: '',
    code: '',
  }
  emailLoginForm.value = {
    email: '',
    code: '',
  }
  passwordLoginForm.value = {
    account: '',
    password: '',
  }
}

// 登录
function handleLoginSubmit(method: LoginMethod) {
  if (!isAgreeTerms.value) {
    showAgreeTermsDialog.value = true
    return
  }

  let payload: LoginPayload = {
    loginChannel: 'MEMBER_PLATFOMR_PW',
    account: '',
    password: '',
  }

  new Promise((resolve) => {
    switch (method) {
      case 'password':
        {
          passwordLoginFormRef.value?.validate((errors) => {
            if (errors) return ''

            payload = {
              loginChannel: 'MEMBER_PLATFOMR_PW',
              account: passwordLoginForm.value.account,
              password: SparkMD5.hash(passwordLoginForm.value.password),
            }

            resolve(true)
          })
        }
        break
      case 'sms':
        {
          smsLoginFormRef.value?.validate((errors) => {
            if (errors) return ''

            payload = {
              loginChannel: 'MEMBER_PLATFOMR_SMS',
              account: smsLoginForm.value.phoneNumber,
              authCode: smsLoginForm.value.code,
            }

            resolve(true)
          })
        }
        break
      case 'email':
        {
          emailLoginFormRef.value?.validate((errors) => {
            if (errors) return ''

            payload = {
              loginChannel: 'MEMBER_PLATFOMR_EMAIL',
              account: emailLoginForm.value.email,
              authCode: emailLoginForm.value.code,
            }

            resolve(true)
          })
        }
        break
    }
  }).then(() => {
    loginBtnLoading.value = true

    fetchLogin<UserInfo & { token: string }>(payload)
      .then((res) => {
        if (res.code !== 0) return ''

        userStore.updateToken(res.data.token)
        userStore.updateUserInfo({
          avatarUrl: res.data.avatarUrl,
          memberId: res.data.memberId,
          mobilePhone: res.data.mobilePhone,
          nickName: res.data.nickName,
          remark: res.data.remark,
          email: res.data.email,
        })

        const redirectUrl = decodeURIComponent((route.query.redirect as string) || '')
        router.replace({ path: redirectUrl ? redirectUrl : '/' })

        window.$message.success(t('login_module.login_success'))

        ss.remove(StorageKeyEnum.smsCountdownTime)
        ss.remove(StorageKeyEnum.emailCountdownTime)
      })
      .finally(() => {
        loginBtnLoading.value = false
      })
  })
}

function handleAgreeAndContinue() {
  showAgreeTermsDialog.value = false
  isAgreeTerms.value = true
  handleLoginSubmit(currentLoginMethod.value)
}

// 打开用户协议
function handleOpenUserAgreement() {
  window.open(userAgreementUrl.value, '_blank')
}

// 打开隐私协议
function handleOpenPrivacyPolicy() {
  window.open(privacyPolicyUrl.value, '_blank')
}
</script>

<template>
  <div
    class="bg-px-login-h5_login_bg-png relative flex h-full w-full flex-col justify-between bg-cover bg-center bg-no-repeat py-[44px]"
  >
    <div class="px-[33px]">
      <p class="font-family-medium text-[18px]">{{ t('login_module.mobile_welcome_words') }}</p>

      <p class="text-gray-font-color mt-[9px] text-[12px]">{{ t('login_module.sign_in_with_mobile_number') }}</p>

      <div class="text-theme-color border-b-theme-color font-family-medium my-[24px] inline-block text-[13px]">
        <span>{{ currentLoginMethodValue }}</span>
        <div class="bg-theme-color h-[2px] w-full rounded-[1px]" />
      </div>

      <!-- SMS登录 -->
      <n-form
        v-if="currentLoginMethod === 'sms'"
        ref="smsLoginFormRef"
        label-placement="left"
        size="large"
        :model="smsLoginForm"
        :rules="smsLoginFormRules"
      >
        <n-form-item path="phoneNumber" feedback-class="text-[12px]!">
          <n-input
            v-model:value.trim="smsLoginForm.phoneNumber"
            :allow-input="onlyAllowNumber"
            :maxlength="currentPhoneNumberArea === '+852' ? 8 : 11"
            :placeholder="t('login_module.please_enter_your_cell_phone_number')"
          >
            <template #prefix>
              <div class="flex items-center">
                <n-popselect v-model:value="currentPhoneNumberArea" :options="phoneNumberAreaOptions" trigger="click">
                  <div class="flex w-[54px] cursor-pointer items-center">
                    <div class="mr-[4px] text-[14px]">{{ currentPhoneNumberArea }}</div>

                    <Down theme="outline" size="18" fill="#333" :stroke-width="3" class="mt-[2px]" />
                  </div>
                </n-popselect>

                <div class="mx-[8px] h-[18px] w-[1px] bg-[#868686]"></div>
              </div>
            </template>
          </n-input>
        </n-form-item>
        <n-form-item path="code" feedback-class="text-[12px]!">
          <n-input
            v-model:value="smsLoginForm.code"
            :allow-input="onlyAllowNumber"
            show-password-on="click"
            :maxlength="6"
            :placeholder="t('login_module.please_enter_the_verification_code')"
          >
          </n-input>
          <n-button
            v-show="!isShowCountdown"
            class="text-[11px]! ml-[9px]! text-[#333]! px-[10px]! bg-white!"
            :class="isEnglishLanguage ? 'w-[70px]!' : 'w-[90px]!'"
            :disabled="!smsLoginForm.phoneNumber"
            @click="handleSMSCodeGain"
          >
            <span>{{ t('common_module.get_code') }}</span>
          </n-button>
          <div
            v-show="isShowCountdown"
            class="flex-center rounded-theme ml-[9px]! text-gray-font-color h-[40px] flex-shrink-0 border bg-white text-center text-[12px]"
            :class="isEnglishLanguage ? 'w-[70px]' : 'w-[90px]'"
          >
            <n-countdown
              ref="countdownRef"
              :duration="countdownDuration"
              :active="countdownActive"
              :render="countdownRender"
              :on-finish="onCountdownFinish"
            />
          </div>
        </n-form-item>
        <n-form-item class="mt-4">
          <n-button
            type="primary"
            size="large"
            block
            :loading="loginBtnLoading"
            :disabled="!smsLoginForm.phoneNumber || !smsLoginForm.code"
            :focusable="false"
            @click="handleLoginSubmit('sms')"
          >
            {{ t('common_module.login') }}
          </n-button>
        </n-form-item>
      </n-form>

      <!-- 密码登录 -->
      <n-form
        v-if="currentLoginMethod === 'password'"
        ref="passwordLoginFormRef"
        label-placement="left"
        size="large"
        :model="passwordLoginForm"
        :rules="passwordLoginFormRules"
        feedback-class="text-[12px]!"
      >
        <n-form-item path="account" feedback-class="text-[12px]!">
          <n-input
            v-model:value="passwordLoginForm.account"
            :allow-input="noSideSpace"
            :maxlength="50"
            :placeholder="t('login_module.please_enter_your_account_number')"
          />
        </n-form-item>
        <n-form-item path="password" feedback-class="text-[12px]!">
          <n-input
            v-model:value="passwordLoginForm.password"
            class="font-sans"
            :allow-input="noSideSpace"
            type="password"
            show-password-on="click"
            :placeholder="t('login_module.please_enter_your_password')"
          />
        </n-form-item>

        <div class="flex w-full justify-end">
          <span class="text-[11px] text-[#518AFF]" @click="handleToResetPassword">
            {{ t('login_module.forgot_password') }}
          </span>
        </div>

        <n-form-item class="mt-4">
          <n-button
            type="primary"
            size="large"
            block
            :loading="loginBtnLoading"
            :disabled="!passwordLoginForm.account || !passwordLoginForm.password"
            :focusable="false"
            @click="handleLoginSubmit('password')"
          >
            {{ t('common_module.login') }}
          </n-button>
        </n-form-item>
      </n-form>

      <!-- 邮箱登录 -->
      <n-form
        v-if="currentLoginMethod === 'email'"
        ref="emailLoginFormRef"
        label-placement="left"
        size="large"
        :model="emailLoginForm"
        :rules="emailLoginFormRules"
      >
        <n-form-item path="email" feedback-class="text-[12px]!">
          <n-input
            v-model:value="emailLoginForm.email"
            :allow-input="noSideSpace"
            :placeholder="t('login_module.please_enter_your_email_address')"
            :maxlength="50"
          >
          </n-input>
        </n-form-item>
        <n-form-item path="code" feedback-class="text-[12px]!">
          <n-input
            v-model:value="emailLoginForm.code"
            :allow-input="onlyAllowNumber"
            show-password-on="click"
            :maxlength="6"
            :placeholder="t('login_module.please_enter_the_verification_code')"
          >
          </n-input>

          <n-button
            v-show="!isShowCountdown"
            class="text-[11px]! ml-[9px]! text-[#333]! px-[10px]! bg-white!"
            :class="isEnglishLanguage ? 'w-[70px]!' : 'w-[90px]!'"
            :disabled="!emailLoginForm.email"
            @click="handleEmailCodeGain"
          >
            <span>{{ t('common_module.get_code') }}</span>
          </n-button>
          <div
            v-show="isShowCountdown"
            class="flex-center rounded-theme ml-[9px]! text-gray-font-color h-[40px] flex-shrink-0 border bg-white text-center text-[12px]"
            :class="isEnglishLanguage ? 'w-[70px]' : 'w-[90px]'"
          >
            <n-countdown
              ref="countdownRef"
              :duration="countdownDuration"
              :active="countdownActive"
              :render="countdownRender"
              :on-finish="onCountdownFinish"
            />
          </div>
        </n-form-item>
        <n-form-item class="mt-4">
          <n-button
            type="primary"
            size="large"
            block
            :loading="loginBtnLoading"
            :disabled="!emailLoginForm.email || !emailLoginForm.code"
            :focusable="false"
            @click="handleLoginSubmit('email')"
          >
            {{ t('common_module.login') }}
          </n-button>
        </n-form-item>
      </n-form>

      <div class="flex-center gap-[7px] text-[11px]">
        <n-checkbox v-model:checked="isAgreeTerms" class="h-[12px] w-[12px]" />
        <div>
          {{ t('login_module.agreement_prefix') }}
          <span class="text-[#518AFF]" @click="handleOpenUserAgreement">{{ t('login_module.agreement_terms') }}</span>
          {{ t('login_module.agreement_and') }}
          <span class="text-[#518AFF]" @click="handleOpenPrivacyPolicy">{{ t('login_module.agreement_privacy') }}</span>
        </div>
      </div>
    </div>

    <div class="absolute top-[450px] w-full px-[33px]">
      <div class="mb-[44px] flex flex-col items-center">
        <n-divider class="w-[70%]!">
          <span class="text-gray-font-color text-[11px]">{{ t('login_module.other_login_methods') }}</span>
        </n-divider>

        <div class="flex-center gap-[15px]">
          <div
            v-show="currentLoginMethod !== 'password'"
            class="flex-center h-[34px] w-[34px] cursor-pointer rounded-full bg-[#F2F2F2]"
            @click="handleLoginMethodChange('password')"
          >
            <Lock theme="outline" size="16" fill="#000DFF" :stroke-width="3" />
          </div>
          <div
            v-show="currentLoginMethod !== 'email'"
            class="flex-center h-[34px] w-[34px] cursor-pointer rounded-full bg-[#F2F2F2]"
            @click="handleLoginMethodChange('email')"
          >
            <Mail theme="outline" size="16" fill="#000DFF" :stroke-width="3" />
          </div>

          <div
            v-show="currentLoginMethod !== 'sms'"
            class="flex-center h-[34px] w-[34px] cursor-pointer rounded-full bg-[#F2F2F2]"
            @click="handleLoginMethodChange('sms')"
          >
            <Phone theme="outline" size="16" fill="#000DFF" :stroke-width="3" />
          </div>
        </div>
      </div>
    </div>

    <van-dialog v-model:show="showAgreeTermsDialog" :title="t('login_module.please_review_and_accept_the_agreement')">
      <div class="my-[16px] flex justify-center gap-[6px] text-center">
        <span class="text-[14px] text-[#518AFF]" @click="handleOpenUserAgreement">
          {{ agreementPrefix }}{{ t('login_module.agreement_terms') }}{{ agreementSuffix }}
        </span>

        <span class="text-[14px] text-[#518AFF]" @click="handleOpenPrivacyPolicy">
          {{ agreementPrefix }}{{ t('login_module.agreement_privacy') }}{{ agreementSuffix }}
        </span>
      </div>

      <template #footer>
        <div class="flex flex-col gap-[8px] px-[24px] pb-[8px] pt-[8px]">
          <van-button type="primary" color="#000DFF" round class="h-[36px]" @click="handleAgreeAndContinue">
            {{ t('login_module.agree_and_continue') }}
          </van-button>

          <span
            class="text-gray-font-color h-[28px] text-center text-[14px] leading-7"
            @click="showAgreeTermsDialog = false"
          >
            {{ t('login_module.disagree') }}
          </span>
        </div>
      </template>
    </van-dialog>
  </div>
</template>

<style lang="scss" scoped>
:deep(.n-checkbox-box-wrapper),
:deep(.n-checkbox-box) {
  width: 12px !important;
  height: 12px !important;
  border-radius: 100% !important;
}

:deep(.--n-feedback-height) {
  height: 16px !important;
}

:deep(.n-input__placeholder) {
  font-size: 13px !important;
}
</style>
