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

enum StorageKeyEnum {
  smsCountdownTime = 'SMS_COUNTDOWN_TIME',
  emailCountdownTime = 'MAIL_COUNTDOWN_TIME',
}
type LoginMethod = 'password' | 'sms' | 'email' | 'google'
interface LoginPayload {
  loginChannel: 'MEMBER_PLATFOMR_SMS' | 'MEMBER_PLATFOMR_EMAIL' | 'MEMBER_PLATFOMR_PW' | 'MEMBER_PLATFOMR_GOOGLE'
  account: string
  password?: string
  authCode?: string
}

const userStore = useUserStore()
const systemLanguageStore = useSystemLanguageStore()
const router = useRouter()
const route = useRoute()
const { t } = useI18n()

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

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

const loginBtnLoading = ref(false)

const passwordLoginForm = ref({
  account: '',
  password: '',
})
const smsLoginForm = ref({
  phoneNumber: '',
  code: '',
})
const emailLoginForm = ref({
  email: '',
  code: '',
})
const googleLoginForm = ref({
  credential: '',
})

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
    },
  },
  code: { required: true, message: t('login_module.please_enter_the_verification_code') },
})
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
    },
  },
  code: { required: true, message: t('login_module.please_enter_the_verification_code') },
})

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

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

const isAgreeAgreement = ref(false)

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

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
    }
  }
})

/* created */
;(function () {
  if (!window.google) {
    const script = document.createElement('script')
    script.src = `https://accounts.google.com/gsi/client?hl=${systemLanguageStore.currentLanguage}` // 加载客户端库
    script.async = true
    script.onload = () => {
      getGoogleLoginClientId().then((clientId) => {
        clientId && initializeGoogleSignIn(clientId)
      })
    }
    document.head.appendChild(script)
  } else {
    getGoogleLoginClientId().then((clientId) => {
      clientId && initializeGoogleSignIn(clientId)
    })
  }
})()

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 onCardReserveAnimationEnd() {
  showCardReserveAnimation.value = false
}

function onCountdownFinish() {
  isShowCountdown.value = false
}

function getInputPhoneNumber() {
  return currentPhoneNumberArea.value !== '+86'
    ? encodeURIComponent(`${currentPhoneNumberArea.value}${smsLoginForm.value.phoneNumber}`)
    : smsLoginForm.value.phoneNumber
}

function handleLoginSubmit(method: LoginMethod) {
  if (!isAgreeAgreement.value) {
    window.$message.warning(t('login_module.please_review_and_accept_the_agreement'))
    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
      case 'google':
        {
          payload = {
            loginChannel: 'MEMBER_PLATFOMR_GOOGLE',
            account: '',
            authCode: googleLoginForm.value.credential,
          }

          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 handleLoginMethodChange(method: LoginMethod) {
  showCardReserveAnimation.value = true

  setTimeout(() => {
    currentLoginMethod.value = method
  }, 500)
}

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 initializeGoogleSignIn(clientId: string) {
  window.google.accounts.id.initialize({
    client_id: encodeURIComponent(clientId),
    auto_select: false,
    callback: (res: { credential: string; clientId: string }) => {
      googleLoginForm.value.credential = res.credential

      handleLoginSubmit('google')
    },
  })

  if (googleLoginBtnRef.value) {
    window.google.accounts.id.renderButton(googleLoginBtnRef.value, {
      size: 'medium',
      text: 'signin_with',
      logo_alignment: 'left',
      locale: systemLanguageStore.currentLanguage,
    })

    googleLoginBtnLoading.value = true
  }

  // window.google.accounts.id.prompt((notification: any) => {
  //   if (notification.isNotDisplayed() || notification.isSkippedMoment()) {
  //     console.log('💥💥💥💥💥💥登录失败💥💥💥💥💥💥')
  //   }
  // })
}

function getGoogleLoginClientId() {
  return fetchGoogleClientId<string>().then((res) => {
    if (res.code !== 0) return ''

    return res.data
  })
}

function handleAgreementNavigator(name: 'UserAgreement' | 'PrivacyPolicy') {
  if (name === 'UserAgreement') {
    window.open('https://tcn9nhw8kfwe.feishu.cn/wiki/Y1ELwRVESi9jw9kshc0chT2ZnSf?fromScene=spaceOverview', '_blank')
  } else if (name === 'PrivacyPolicy') {
    window.open('https://tcn9nhw8kfwe.feishu.cn/wiki/OBzxwhGBviHP8lk9ca0chUh9nCc?fromScene=spaceOverview', '_blank')
  }
}
</script>

<template>
  <div class="bg-px-login_bg-png relative h-screen min-h-[750px] w-full min-w-[600px] bg-cover bg-center bg-no-repeat">
    <div
      class="bg-px-logo-png z-100 absolute left-[60px] top-[25px] h-[29px] w-[119px] !bg-contain bg-center bg-no-repeat"
    ></div>

    <div class="z-100 absolute right-[60px] top-[25px] w-[140px]">
      <LanguageSetting arrow-direction="bottom" btn-bg-color="#f4f5f5" />
    </div>

    <div class="absolute right-[14%] top-1/2 w-[390px] -translate-y-1/2">
      <div
        class="h-full w-full rounded-[10px] bg-[#fff] px-[29px] shadow-2xl"
        :class="{ 'animate-card-reverse': showCardReserveAnimation }"
        style="transform-style: preserve-3d"
        @animationend="onCardReserveAnimationEnd"
      >
        <h1 class="font-600 py-[34px] text-center text-[22px]">{{ t('login_module.app_welcome_words') }}</h1>

        <div>
          <!-- 密码登录 -->
          <n-form
            v-if="currentLoginMethod === 'password'"
            ref="passwordLoginFormRef"
            label-placement="left"
            size="large"
            :model="passwordLoginForm"
            :rules="passwordLoginFormRules"
          >
            <n-form-item path="account">
              <n-input
                v-model:value="passwordLoginForm.account"
                :allow-input="noSideSpace"
                :maxlength="50"
                :placeholder="t('login_module.please_enter_your_account_number')"
              >
                <template #prefix>
                  <div class="mr-[6px]">
                    <User theme="outline" size="16" fill="#868686" :stroke-width="3" />
                  </div>
                </template>
              </n-input>
            </n-form-item>
            <n-form-item path="password">
              <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')"
              >
                <template #prefix>
                  <div class="mr-[6px]">
                    <Lock theme="outline" size="16" fill="#868686" :stroke-width="3" />
                  </div>
                </template>
              </n-input>
            </n-form-item>
            <n-form-item class="mt-4">
              <n-button
                type="primary"
                size="large"
                block
                :loading="loginBtnLoading"
                :disabled="!passwordLoginForm.account || !passwordLoginForm.password"
                @click="handleLoginSubmit('password')"
              >
                {{ t('common_module.login') }}
              </n-button>
            </n-form-item>
          </n-form>

          <!-- SMS登录 -->
          <n-form
            v-if="currentLoginMethod === 'sms'"
            ref="smsLoginFormRef"
            label-placement="left"
            size="large"
            :model="smsLoginForm"
            :rules="smsLoginFormRules"
          >
            <n-form-item path="phoneNumber">
              <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-[62px] cursor-pointer items-center">
                        <div class="mr-[4px]">{{ currentPhoneNumberArea }}</div>

                        <Down theme="outline" size="18" fill="#333" :stroke-width="3" />
                      </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">
              <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')"
              >
                <template #suffix>
                  <div class="flex items-center">
                    <div class="ml-[6px] mr-[10px] h-[18px] w-[1px] bg-[#868686]"></div>

                    <div class="text-end">
                      <button
                        v-show="!isShowCountdown"
                        class="cursor-pointer text-[11px] text-[#333] transition active:text-[#6A6A6A]"
                        @click="handleSMSCodeGain"
                      >
                        {{ t('login_module.get_verification_code') }}
                      </button>
                      <div v-show="isShowCountdown" class="inline-block w-[50px] text-center">
                        <n-countdown
                          ref="countdownRef"
                          :duration="countdownDuration"
                          :active="countdownActive"
                          :render="countdownRender"
                          :on-finish="onCountdownFinish"
                        />
                      </div>
                    </div>
                  </div>
                </template>
              </n-input>
            </n-form-item>
            <n-form-item class="mt-4">
              <n-button
                type="primary"
                size="large"
                block
                :loading="loginBtnLoading"
                :disabled="!smsLoginForm.phoneNumber || !smsLoginForm.code"
                @click="handleLoginSubmit('sms')"
              >
                {{ 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">
              <n-input
                v-model:value="emailLoginForm.email"
                :allow-input="noSideSpace"
                :placeholder="t('login_module.please_enter_your_email_address')"
                :maxlength="50"
              >
                <template #prefix>
                  <div class="mr-[6px]">
                    <Mail theme="outline" size="16" fill="#868686" :stroke-width="3" />
                  </div>
                </template>
              </n-input>
            </n-form-item>
            <n-form-item path="code">
              <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')"
              >
                <template #suffix>
                  <div class="flex items-center">
                    <div class="ml-[6px] mr-[10px] h-[18px] w-[1px] bg-[#868686]"></div>

                    <div class="text-end">
                      <button
                        v-show="!isShowCountdown"
                        class="cursor-pointer text-[11px] text-[#333] transition active:text-[#6A6A6A]"
                        @click="handleEmailCodeGain"
                      >
                        {{ t('login_module.get_verification_code') }}
                      </button>

                      <div v-show="isShowCountdown" class="inline-block w-[50px] text-center">
                        <n-countdown
                          ref="countdownRef"
                          :duration="countdownDuration"
                          :active="countdownActive"
                          :render="countdownRender"
                          :on-finish="onCountdownFinish"
                        />
                      </div>
                    </div>
                  </div>
                </template>
              </n-input>
            </n-form-item>
            <n-form-item class="mt-4">
              <n-button
                type="primary"
                size="large"
                block
                :loading="loginBtnLoading"
                :disabled="!emailLoginForm.email || !emailLoginForm.code"
                @click="handleLoginSubmit('email')"
              >
                {{ t('common_module.login') }}
              </n-button>
            </n-form-item>
          </n-form>
        </div>

        <div class="w-full pb-[34px]">
          <div class="h-[134px]">
            <div class="mb-[12px] text-center text-[12px] text-[#999999]">
              {{ t('login_module.other_login_methods') }}
            </div>
            <div class="flex items-center justify-center">
              <button
                v-show="currentLoginMethod !== 'email'"
                class="mx-[10px] flex h-[34px] w-[34px] items-center justify-center rounded-full bg-[#f1f1f1] transition hover:bg-[#e0e0e0]"
                @click="handleLoginMethodChange('email')"
              >
                <Mail theme="outline" size="18" fill="#666666" :stroke-width="3" />
              </button>

              <button
                v-show="currentLoginMethod !== 'sms'"
                class="mx-[10px] flex h-[34px] w-[34px] items-center justify-center rounded-full bg-[#f1f1f1] transition hover:bg-[#e0e0e0]"
                @click="handleLoginMethodChange('sms')"
              >
                <Iphone theme="outline" size="17" fill="#666666" :stroke-width="3" />
              </button>

              <button
                v-show="currentLoginMethod !== 'password'"
                class="mx-[10px] flex h-[34px] w-[34px] items-center justify-center rounded-full bg-[#f1f1f1] transition hover:bg-[#e0e0e0]"
                @click="handleLoginMethodChange('password')"
              >
                <Lock theme="outline" size="17" fill="#666666" :stroke-width="3" />
              </button>
            </div>

            <div v-show="googleLoginBtnLoading" class="py-[10px] text-center text-[12px] text-[#999999]">
              {{ t('common_module.or') }}
            </div>

            <div v-show="googleLoginBtnLoading" class="flex-center flex">
              <div ref="googleLoginBtnRef"></div>
            </div>
          </div>

          <div class="flex-center mt-[16px] flex select-none text-center">
            <n-checkbox v-model:checked="isAgreeAgreement" />

            <span class="pl-[5px] text-[12px] leading-[23px]">
              <span>{{ t('login_module.agreement_prefix') }}</span>
              <span class="cursor-pointer text-[#518AFF]" @click="handleAgreementNavigator('UserAgreement')"
                >《{{ t('login_module.agreement_terms') }}》</span
              >
              <span>{{ t('login_module.agreement_and') }}</span>
              <span class="cursor-pointer text-[#518AFF]" @click="handleAgreementNavigator('PrivacyPolicy')"
                >《{{ t('login_module.agreement_privacy') }}》</span
              >
            </span>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
