<script setup lang="ts">
import type { FormInstance } from 'vant'
import { LoginStateEnum, useFormRules, useLoginState } from '@af-mobile-client-vue3/hooks/useLogin'
import GetAppDataService from '@af-mobile-client-vue3/plugins/AppData'
import { runLogic } from '@af-mobile-client-vue3/services/api/common'
import { getUserPermissions } from '@af-mobile-client-vue3/services/api/search'
import { useSettingStore } from '@af-mobile-client-vue3/stores/modules/setting'
import { useUserStore } from '@af-mobile-client-vue3/stores/modules/user'
import { UserType } from '@af-mobile-client-vue3/types/auth'
import { checkAndInitDrivingConfig } from '@af-mobile-client-vue3/utils/driving/drivingUtils'
import { handleLoginPasswordCheck } from '@af-mobile-client-vue3/utils/login/loginVerify'
import { mobileUtil } from '@af-mobile-client-vue3/utils/mobileUtil'
import { isWechat } from '@af-mobile-client-vue3/utils/platform-auth'
import { funcToRouter, loadRoutes } from '@af-mobile-client-vue3/utils/routerUtil'
import { secureStorageBatchWrite, secureStorageRead } from '@af-mobile-client-vue3/utils/secureStorage'
import bcrypt from 'bcryptjs'
import { closeToast, showDialog, showFailToast, showLoadingToast, showSuccessToast, showToast, Switch, Button as VanButton, Col as VanCol, Field as VanField, Form as VanForm, Icon as VanIcon, Loading as VanLoading, Row as VanRow } from 'vant'

import { computed, inject, onBeforeMount, onMounted, reactive, ref, unref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import 'vant/lib/switch/index.css'

declare let WeixinJSBridge: any
const { setLoginState, getLoginState } = useLoginState()
const { getFormRules } = useFormRules()
const userState = useUserStore()
const router = useRouter()

const formRef = ref<FormInstance>()
const loading = ref(false)
const wxloading = ref(false)
const rememberMe = ref(false)
const switchPassType = ref(true)
const formData = reactive({
  username: '',
  password: '',
})
const route = useRoute()
const setting = useSettingStore()

// 判断是否为af-wechat项目
const isAfWechatProject = computed(() => {
  // 可以根据项目特定标识判断，例如环境变量或setting中的配置
  // 这里使用环境变量作为示例，您可以根据实际情况调整
  return import.meta.env.VITE_APP_SYSTEM_NAME === 'af-wechat' || setting.getSetting()?.hiddenTraditionalLogin
})

// 判断是否显示传统登录表单
const showTraditionalLoginForm = computed(() => {
  // 如果不是微信环境，或者不是af-wechat项目，则显示传统登录表单
  if (!isWechat() || !isAfWechatProject.value) {
    return true
  }
  // 如果是微信环境且是af-wechat项目，则检查是否开启了微信登录
  // 如果没开启微信登录，则仍显示传统登录表单
  if (!setting.getSetting()?.wechatLogin) {
    return true
  }
  // 微信环境且是af-wechat项目/隐藏登录表单且开启了微信登录，则隐藏传统登录表单
  return false
})

const getShow = computed(() => (unref(getLoginState) === LoginStateEnum.LOGIN))

const login: any = inject('$login')
onBeforeMount(async () => {
  if (isWechat() && setting.getSetting()?.wxAutoLogin) {
    // 检测是否要开放微信登录
    if (setting.getSetting()?.wechatLogin) {
      try {
        wxloading.value = true
        if (route.query.code && route.query.state) {
          await wxLoginFunContinue(route.query.code, route.query.state)
        }
        else {
          await wxLoginFun()
        }
      }
      catch {
        await showDialog({ message: '当前用户无登录权限' })
        closeWindows()
      }
      finally {
        wxloading.value = false
      }
    }
  }
})

// 面部识别登录 返回特性信息
async function isFaceRecognition() {
  return await new Promise<{ success: boolean, embedding: number[] }>((resolve) => {
    mobileUtil.execute({
      param: {
        scene: '面部识别认证',
        liveness: 'nod', // nod 点头, blink 眨眼
      },
      funcName: 'verifyFace',
      callbackFunc: async (result: any) => {
        if (result.status === 'success' && result.data?.embedding) {
          resolve({ success: true, embedding: result.data.embedding })
          return
        }
        resolve({ success: false, embedding: null })
        // resolve({ success: true, embedding: qmzFace })
      },
    })
  })
}

// 开启定时面别识别
function startIntervalFaceRecognition() {
  mobileUtil.execute({
    param: {
      scene: '面部识别认证',
      liveness: 'nod',
      intervalMinutes: setting.getSetting()?.faceIntervalMinutes || 1,
      retryCount: setting.getSetting()?.faceRetryCount || 3,
    },
    funcName: 'startPeriodicFaceVerify',
    callbackFunc: async (result: any) => {
      if (result.status === 'success' && result.data.success && !result.data.success) {
        showSuccessToast('认证成功')
      }
      else if (result.status === 'success' && !result.data.success) {
        showFailToast('面部识别认证失败, 请重新登录')
        mobileUtil.execute({
          param: {},
          funcName: 'stopPeriodicFaceVerify',
          callbackFunc: async () => {
          },
        })
        userState.logout()
      }
    },
  })
}

function handleSubmit() {
  formRef.value
    ?.validate()
    .then(async () => {
      try {
        loading.value = true
        showLoadingToast('登录中...')
        const username = formData.username
        const password = formData.password
        if (setting.getSetting()?.phoneLoginVerification) {
          const ver = await runLogic('openapi/loginVerification', { username, password }) as any
          if (!ver.success) {
            closeToast()
            loading.value = false
            showFailToast(ver.msg || '认证失败')
            return
          }
        }
        const data: any = await userState.Login({
          username,
          password: bcrypt.hashSync(password, 10),
          resourceName: setting.getSetting()?.routerName || '智慧手机',
        })
        // 处理登录成功后的逻辑
        login.f = data
        await Promise.all([GetAppDataService.load()])
        // 处理密码校验和弹窗
        const passwordCheckPassed = await handleLoginPasswordCheck(formData.username, formData.password)
        if (!passwordCheckPassed) {
          // 用户取消修改密码，停止登录流程
          closeToast()
          loading.value = false
          return
        }
        const loginInfo = {
          f: login.f,
          jwt: login.f.id,
          r: login.r,
        }
        userState.setLogin(loginInfo)
        const compatible = import.meta.env.VITE_APP_COMPATIBLE
        if (compatible === 'OA')
          await afterGeneral(data)
        else
          if (data.resources.data)
            await afterGeneral(data.resources.data, data.access_token)
          else
            await afterGeneral(data.resources, data.access_token)

        // 面别识别登录
        if (setting.getSetting()?.isFaceRecognition) {
          const faceRes = await isFaceRecognition()
          if (!faceRes.success) {
            showFailToast('面部识别认证失败')
            return
          }
          const matchRes = await runLogic('matchFaceEmbedding', {
            userId: login.f.resources.id,
            embedding: faceRes.embedding,
          }, 'af-system') as any
          if (!matchRes.isMatch) {
            showFailToast(matchRes.msg || '面部识别认证失败')
            return
          }
          const toPath = decodeURIComponent((route.query?.redirect || '/appointment-progress') as string)
          closeToast()
          if (route.name === '/login')
            await router.replace('/appointment-progress')
          else await router.replace(toPath)

          if (setting.getSetting()?.intervalFaceRecognition) {
            startIntervalFaceRecognition()
          }
        }
        else {
          const toPath = decodeURIComponent((route.query?.redirect || '/appointment-progress') as string)
          closeToast()
          if (route.name === '/login')
            await router.replace('/appointment-progress')
          else await router.replace(toPath)
        }
      }
      finally {
        loading.value = false
      }
    })
    .catch((e) => {
      showFailToast(e.message || '用户名或密码错误')
    })
}

// 面别识别登录
async function faceSubmit() {
  try {
    loading.value = true
    showLoadingToast('面部识别登录中...')
    const faceRes = await isFaceRecognition()
    if (!faceRes.success) {
      showFailToast('面部识别认证失败')
      return
    }
    const data: any = await userState.faceLogin({
      embedding: JSON.stringify(faceRes.embedding),
      resourceName: setting.getSetting()?.routerName || '智慧手机',
      isMobile: true,
    })
    if (!data.success) {
      showFailToast(data.msg || '面部识别登录暂不可用')
    }
    showToast({
      message: `当前登陆人: ${data.resources.name}`,
      duration: 3000, // 停留 3秒
    })
    login.f = data
    await Promise.all([GetAppDataService.load()])
    const loginInfo = {
      f: login.f,
      jwt: login.f.id,
      r: login.r,
    }
    userState.setLogin(loginInfo)
    if (data.resources.data)
      await afterGeneral(data.resources.data, data.access_token)
    else
      await afterGeneral(data.resources, data.access_token)

    const toPath = decodeURIComponent((route.query?.redirect || '/appointment-progress') as string)
    if (route.name === '/login')
      await router.replace('/appointment-progress')
    else
      await router.replace(toPath)

    if (setting.getSetting()?.intervalFaceRecognition) {
      startIntervalFaceRecognition()
    }
  }
  catch (e: any) {
    showFailToast(e?.msg || '面部识别登录暂不可用')
  }
  finally {
    loading.value = false
  }
}

function closeWindows() {
  if (isWechat()) {
    (window as any).WeixinJSBridge.call('closeWindow')
  }
  else {
    // 关闭页面
    if (navigator.userAgent.includes('Firefox') || navigator.userAgent.includes('Chrome')) {
      window.open('about:blank', '_self')
      window.close()
    }
    else {
      window.opener = null
      window.open('', '_self')
      window.close()
    }
  }
}

async function afterGeneral(result, token = '') {
  // 排序 functions 及其嵌套的 children
  if (result.functions && Array.isArray(result.functions)) {
    // 对顶层菜单进行排序
    result.functions.sort((a, b) => (a.position || 0) - (b.position || 0))

    // 对每个菜单的子项进行排序
    for (const item of result.functions) {
      if (item.children && Array.isArray(item.children)) {
        item.children.sort((a, b) => (a.position || 0) - (b.position || 0))
      }
    }
  }

  const user: any = {
    ...result,
    username: result.ename,
    avatar: result.avatar ? result.avatar : setting.getSetting()?.defaultAvatarUrl,
  }
  userState.setUserInfo(user)
  // 设置用户类型为系统用户（传统登录方式）
  userState.setUserType(UserType.SYSTEM)
  // 如果result中没有返回 权限 需要主动获取权限列表
  if (!result.permissions) {
    result.permissions = await getUserPermissions(result.id)
  }
  userState.setPermissions(result.permissions)
  userState.setRoles([{ id: 'admin', operation: ['add', 'edit', 'delete'] }])
  // 加载路由
  loadRoutes(funcToRouter(user.functions))

  // 存储登录数据到本地缓存
  secureStorageBatchWrite([
    {
      key: 'loginData',
      value: {
        username: formData.username,
        password: formData.password,
        rememberMe: rememberMe.value,
        token,
      },
    },
    {
      key: 'userData',
      value: result,
    },
  ])

  // 每次重新登录时，清除indexedDB缓存
  // indexedDB.clear()
  // 如果不是微信和OA 进行超速相关判断
  checkAndInitDrivingConfig(userState)
}
async function wxLoginFun() {
  await localStorage.setItem('wechatLoginPending', 'true')
  userState.getCode(setting.getSetting()?.tenantName)
}
async function wxLoginFunContinue(code, state) {
  try {
    wxloading.value = true
    const data = await userState.loginUnified({
      unifiedCode: `${code}`,
      tenantName: `${state}`,
      loginMode: 'wechat',
      resourceName: setting.getSetting()?.routerName || '智慧手机',
    })
    login.f = data
    await Promise.all([GetAppDataService.load()])
    const loginInfo = {
      f: login.f,
      jwt: login.f.id,
      r: login.r,
    }
    userState.setLogin(loginInfo)
    userState.setTenantName(Array.isArray(route.query.state) ? route.query.state[0] : route.query.state || '')
    await afterGeneral(data.resources)
    const toPath = decodeURIComponent((route.query?.redirect || '/appointment-progress') as string)
    closeToast()
    if (route.name === '/login')
      await router.replace('/appointment-progress')
    else await router.replace(toPath)
  }
  finally {
    wxloading.value = false
  }
}
function getQueryParam(param: string): string | null {
  const search = window.location.search || window.location.hash.split('?')[1] || ''
  const params = new URLSearchParams(search)
  return params.get(param)
}
onMounted(() => {
  const pending = localStorage.getItem('wechatLoginPending')
  const code = getQueryParam('code')
  const state = getQueryParam('state')
  if (pending && code && state) {
    localStorage.removeItem('wechatLoginPending')
    wxLoginFunContinue(code, state)
  }
  try {
    // 手机登录获取本地缓存的登录数据
    secureStorageRead('loginData', (result: any) => {
      if (result.status === 'success') {
        const res = JSON.parse(result.data.value)
        if (res.rememberMe) {
          formData.username = res.username
          formData.password = res.password
          rememberMe.value = res.rememberMe
        }
      }
    })
  }
  catch (e) {
    console.warn('读取本地缓存失败', e)
    // 未拿到跳过
  }
})
</script>

<template>
  <div v-show="wxloading" class="login_form">
    <VanRow justify="center">
      <VanLoading type="spinner" size="30px" vertical color="#1989fa">
        自动登录中...
      </VanLoading>
    </VanRow>
  </div>
  <!-- 微信环境且为af-wechat项目且开启了微信登录时，不显示传统登录表单 -->
  <div v-if="getShow && !wxloading && showTraditionalLoginForm" class="login_form form">
    <VanForm ref="formRef" @submit="handleSubmit">
      <VanField
        v-model="formData.username"
        class="form_field"
        name="username"
        label="账号"
        placeholder="请输入账号"
        label-align="top"
        :rules="getFormRules.username"
      />
      <VanField
        v-model="formData.password"
        class="form_field"
        :type="switchPassType ? 'password' : 'text'"
        name="password"
        label="密码"
        placeholder="请输入密码"
        label-align="top"
        :rules="getFormRules.password"
        @click-right-icon="switchPassType = !switchPassType"
      >
        <template #right-icon>
          <VanIcon v-if="switchPassType" name="closed-eye" color="rgb(56, 149, 250)" />
          <VanIcon v-else name="eye-o" color="rgb(56, 149, 250)" />
        </template>
      </VanField>

      <VanRow justify="space-between" class="extra_setting">
        <VanCol>
          <div class="extra_setting_for_remember_password">
            <Switch v-model="rememberMe" size="12px" />
            <span>记住密码</span>
          </div>
        </VanCol>
        <!--        <VanCol>
          <a class="extra_setting_for_reset_password" @click="setLoginState(LoginStateEnum.RESET_PASSWORD)">忘记密码?</a>
        </VanCol> -->
      </VanRow>
      <VanButton class="login_btn btn" type="primary" block native-type="submit" :loading="loading">
        登 录
      </VanButton>
      <VanButton
        v-if="setting.getSetting()?.isFaceRecognition" class="login_btn_face btn" type="primary" block native-type="button" :loading="loading" @click="faceSubmit"
      >
        扫脸登录
      </VanButton>
    </VanForm>
  </div>

  <!-- 微信环境下的微信登录按钮 -->
  <div v-if="getShow && !wxloading && isWechat() && setting.getSetting()?.wechatLogin" class="form">
    <div v-if="isAfWechatProject && !showTraditionalLoginForm" class="wechat-login-container">
      <VanRow justify="center">
        <VanCol span="24" class="wechat-login-text">
          请使用微信登录
        </VanCol>
      </VanRow>
    </div>
    <VanButton
      v-if="setting.getSetting()?.wxLoginAge"
      class="wechat-login-btn btn"
      type="primary"
      block
      native-type="button"
      :loading="wxloading"
      style="background-color: #07C160; border-color: #07C160; margin-top: 15px"
      @click="wxLoginFun"
    >
      <VanIcon name="wechat" size="20px" />
      微信登录
    </VanButton>
  </div>
</template>

<style scoped lang="less">
@import '@af-mobile-client-vue3/styles/login.less';

.wechat-login-container {
  text-align: center;
  margin: 40px 0 20px 0;

  .wechat-login-text {
    font-size: 16px;
    color: #666;
    margin-bottom: 20px;
  }
}
</style>
