<script lang="ts" setup>
import type { Recordable } from '@vben/types';
import type { AuthApi } from '#/api/core/auth';

import { computed, ref, useTemplateRef } from 'vue';

import { AuthenticationCodeLogin, type VbenFormSchema } from '@vben/common-ui';
import { AuthenticationLogin, z } from '@vben/common-ui';
import { $t } from '@vben/locales';

import { sendVerificationCode } from '#/api';
import { useAuthStore } from '#/store';
import { message } from 'ant-design-vue';

import AccountSelectModal from './AccountSelectModal.vue';

defineOptions({ name: 'Login' });

const loginRef =
  useTemplateRef<InstanceType<typeof AuthenticationCodeLogin>>('loginRef');
const accountSelectRef = useTemplateRef<InstanceType<typeof AccountSelectModal>>(
  'accountSelectRef',
);
const authStore = useAuthStore();
const CODE_LENGTH = 6;

const loading = ref(false);
const pendingAccounts = ref<AuthApi.AccountOption[]>([]);
const selectedAdminId = ref<number | null>(null);

async function resolveAccountSelection(
  accounts: AuthApi.AccountOption[],
  options: {
    defaultAccountId?: number | null;
    defaultAccountType?: string | null;
  } = {},
): Promise<number | null> {
  return new Promise((resolve) => {
    pendingAccounts.value = accounts;
    const defaultId =
      options.defaultAccountId ??
      accounts.find((item) => item.password_matched)?.id ??
      accounts[0]?.id ??
      null;
    selectedAdminId.value = defaultId;
    accountSelectRef.value?.openWithAccounts(accounts, {
      defaultAccountId: options.defaultAccountId,
      defaultAccountType: options.defaultAccountType,
      initialAdminId: defaultId,
    });

    const onConfirm = (account: AuthApi.AccountOption) => {
      resolve(account.id);
    };
    const onCancel = () => resolve(null);

    pendingConfirmHandler.value = onConfirm;
    pendingCancelHandler.value = onCancel;
  });
}

const pendingConfirmHandler = ref<((account: AuthApi.AccountOption) => void) | null>(
  null,
);
const pendingCancelHandler = ref<(() => void) | null>(null);

function handleAccountConfirm(account: AuthApi.AccountOption) {
  pendingConfirmHandler.value?.(account);
  pendingConfirmHandler.value = null;
  pendingCancelHandler.value = null;
}

function handleAccountCancel() {
  pendingCancelHandler.value?.();
  pendingConfirmHandler.value = null;
  pendingCancelHandler.value = null;
}

const formSchema = computed((): VbenFormSchema[] => [
  {
    component: 'VbenInput',
    componentProps: {
      placeholder: '手机号 / 登录账号 / 工号',
    },
    fieldName: 'account',
    label: '账号',
    rules: z.string().min(1, { message: '请输入账号' }),
  },
  {
    component: 'VbenInputPassword',
    componentProps: {
      placeholder: $t('authentication.password'),
    },
    fieldName: 'password',
    label: $t('authentication.password'),
    rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
  },
  {
    component: 'VbenPinInput',
    componentProps: {
      codeLength: CODE_LENGTH,
      createText: (countdown: number) => {
        return countdown > 0
          ? $t('authentication.sendText', [countdown])
          : $t('authentication.sendCode');
      },
      placeholder: $t('authentication.code'),
      handleSendCode: async () => {
        loading.value = true;
        const formApi = loginRef.value?.getFormApi();
        if (!formApi) {
          loading.value = false;
          throw new Error('formApi is not ready');
        }

        try {
          await formApi.validateField('account');
          const accountValid = await formApi.isFieldValid('account');
          if (!accountValid) {
            loading.value = false;
            throw new Error('请输入账号');
          }

          const passwordValid = await formApi.isFieldValid('password');
          if (!passwordValid) {
            loading.value = false;
            throw new Error('密码不符合要求');
          }

          const values = await formApi.getValues();
          let adminId = selectedAdminId.value ?? undefined;
          let result = await sendVerificationCode({
            account: values.account,
            password: values.password,
            admin_id: adminId,
          });

          if (result?.need_select && result.accounts?.length) {
            const pickedId = await resolveAccountSelection(result.accounts, {
              defaultAccountId: result.default_account_id,
              defaultAccountType: result.default_account_type,
            });
            if (!pickedId) {
              throw new Error('请选择要登录的账号');
            }
            selectedAdminId.value = pickedId;
            adminId = pickedId;
            result = await sendVerificationCode({
              account: values.account,
              password: values.password,
              admin_id: adminId,
            });
          }

          if (result) {
            message.success('发送成功，请注意查收');
            if (result.code) {
              message.info(`验证码：${result.code}`, 10);
            }
          }
        } catch (error: any) {
          message.error(error.message || '发送验证码失败');
          throw error;
        } finally {
          loading.value = false;
        }
      },
    },
    fieldName: 'code',
    label: $t('authentication.code'),
    rules: z.string().length(CODE_LENGTH, {
      message: $t('authentication.codeTip', [CODE_LENGTH]),
    }),
  },
]);

async function handleLogin(values: Recordable<any>) {
  const account = (values.account || '').trim();
  if (!account) {
    message.error('请输入账号');
    return;
  }

  let adminId = selectedAdminId.value ?? undefined;
  let result = await authStore.authLogin({
    account,
    password: values.password,
    code: values.code,
    admin_id: adminId,
  });

  if (result?.need_select && result.accounts?.length) {
    const pickedId = await resolveAccountSelection(result.accounts, {
      defaultAccountId: result.default_account_id,
      defaultAccountType: result.default_account_type,
    });
    if (!pickedId) {
      message.warning('请选择要登录的账号');
      return;
    }
    selectedAdminId.value = pickedId;
    await authStore.authLogin({
      account,
      password: values.password,
      code: values.code,
      admin_id: pickedId,
    });
  }
}
</script>

<template>
  <AuthenticationLogin
    ref="loginRef"
    :form-schema="formSchema"
    :loading="authStore.loginLoading"
    :show-code-login="false"
    :show-forget-password="false"
    :show-qrcode-login="false"
    :show-register="false"
    :show-remember-me="false"
    :show-third-party-login="false"
    @submit="handleLogin"
  />
  <AccountSelectModal
    ref="accountSelectRef"
    :accounts="pendingAccounts"
    @confirm="handleAccountConfirm"
    @cancel="handleAccountCancel"
  />
</template>
