<template>
  <div class="login-page" :style="bgStyle">
    <div class="overlay" />

    <div v-if="config?.siteName" class="brand">
      <img :src="config.sysLogo || defaultLogo" class="brand-logo" alt="logo" />
      <h1 class="brand-name">{{ config.siteName }}</h1>
    </div>

    <div v-if="config?.loginTitle" class="brand-title">{{ config.loginTitle }}</div>

    <a-form ref="formRef" :model="form" :rules="rules" class="card">
      <div class="card-header">
        <template v-if="loginType === 'scan'">
          <h2 class="card-title">扫码登录</h2>
        </template>
        <template v-else>
          <h2 class="tab" :class="{ active: loginType === 'sms' }" @click="setLoginType('sms')">
            手机号登录
          </h2>
          <a-divider type="vertical" style="height: 20px" />
          <h2
            class="tab"
            :class="{ active: loginType === 'account' }"
            @click="setLoginType('account')"
          >
            账号登录
          </h2>
        </template>

        <a-button class="switch" type="text" @click="toggleScan" :title="loginType === 'scan' ? '切换到手机号登录' : '切换到扫码登录'">
          <QrcodeOutlined v-if="loginType !== 'scan'" />
          <MobileOutlined v-else />
        </a-button>
      </div>

      <template v-if="loginType === 'account'">
        <a-form-item name="username">
          <a-input v-model:value="form.username" size="large" allow-clear placeholder="账号 / 用户ID">
            <template #prefix><UserOutlined /></template>
          </a-input>
        </a-form-item>

        <a-form-item name="password">
          <a-input-password
            v-model:value="form.password"
            size="large"
            placeholder="登录密码"
            @press-enter="submitAccount"
          >
            <template #prefix><LockOutlined /></template>
          </a-input-password>
        </a-form-item>

        <a-form-item name="code">
          <div class="input-group">
            <a-input
              v-model:value="form.code"
              size="large"
              allow-clear
              :maxlength="5"
              placeholder="验证码"
              @press-enter="submitAccount"
            >
              <template #prefix><SafetyCertificateOutlined /></template>
            </a-input>
            <a-button class="captcha-btn" @click="changeCaptcha">
              <img v-if="captcha" :src="captcha" alt="captcha" />
            </a-button>
          </div>
        </a-form-item>

        <a-form-item>
          <div class="row">
            <a-checkbox v-model:checked="form.remember">记住登录</a-checkbox>
          </div>
        </a-form-item>

        <a-form-item>
          <a-button block size="large" type="primary" :loading="loading" @click="submitAccount">
            {{ loading ? '登录中…' : '登录' }}
          </a-button>
        </a-form-item>
      </template>

      <template v-else-if="loginType === 'sms'">
        <a-form-item name="phone">
          <a-input v-model:value="form.phone" size="large" allow-clear :maxlength="11" placeholder="请输入手机号码">
            <template #addonBefore>+86</template>
          </a-input>
        </a-form-item>

        <a-form-item name="smsCode">
          <div class="input-group">
            <a-input
              v-model:value="form.smsCode"
              size="large"
              allow-clear
              :maxlength="6"
              placeholder="请输入验证码"
              @press-enter="submitSms"
            />
            <a-button class="captcha-btn" :disabled="countdown > 0" @click="openImgCodeModal">
              <span v-if="countdown <= 0">发送验证码</span>
              <span v-else>已发送 {{ countdown }} s</span>
            </a-button>
          </div>
        </a-form-item>

        <a-form-item>
          <a-button block size="large" type="primary" :loading="loading" @click="submitSms">
            {{ loading ? '登录中…' : '登录' }}
          </a-button>
        </a-form-item>
      </template>

      <template v-else>
        <QrLogin @login-success="onQrLoginSuccess" @login-error="onQrLoginError" />
      </template>
    </a-form>

    <div class="copyright">
      <span>© {{ new Date().getFullYear() }}</span>
      <span class="sep">·</span>
      <span>{{ config?.copyright || 'websoft.top Inc.' }}</span>
    </div>

    <a-modal v-model:open="imgCodeModalOpen" :width="340" :footer="null" title="发送验证码">
      <div class="input-group modal-row">
        <a-input
          v-model:value="imgCode"
          size="large"
          allow-clear
          :maxlength="5"
          placeholder="请输入图形验证码"
          @press-enter="sendSmsCode"
        />
        <a-button class="captcha-btn">
          <img alt="captcha" :src="captcha" @click="changeCaptcha" />
        </a-button>
      </div>
      <a-button block size="large" type="primary" :loading="sendingSms" @click="sendSmsCode">
        立即发送
      </a-button>
    </a-modal>

    <a-modal v-model:open="selectUserOpen" :width="520" :footer="null" title="选择账号登录">
      <a-list item-layout="horizontal" :data-source="admins">
        <template #renderItem="{ item }">
          <a-list-item class="list-item" @click="selectUser(item)">
            <a-list-item-meta :description="`租户ID: ${item.tenantId}`">
              <template #title>{{ item.tenantName || item.username }}</template>
              <template #avatar>
                <a-avatar :src="item.avatar" />
              </template>
            </a-list-item-meta>
            <template #actions><RightOutlined /></template>
          </a-list-item>
        </template>
      </a-list>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import { message, type FormInstance } from 'ant-design-vue'
import {
  LockOutlined,
  MobileOutlined,
  QrcodeOutlined,
  RightOutlined,
  SafetyCertificateOutlined,
  UserOutlined
} from '@ant-design/icons-vue'
import QrLogin from '@/components/QrLogin.vue'
import { configWebsiteField, type Config } from '@/api/cms/cmsWebsiteField'
import { getCaptcha, login, loginBySms, sendSmsCaptcha } from '@/api/passport/login'
import type { LoginParam } from '@/api/passport/login/model'
import { listAdminsByPhoneAll } from '@/api/system/user'
import type { User } from '@/api/system/user/model'
import { TEMPLATE_ID } from '@/config/setting'
import { setToken } from '@/utils/token-util'
import type { QrCodeStatusResponse } from '@/api/passport/qrLogin'

definePageMeta({ layout: 'blank' })

const route = useRoute()

const defaultLogo = 'https://oss.wsdns.cn/20240822/0252ad4ed46449cdafe12f8d3d96c2ea.svg'
const config = ref<Config>()
const loading = ref(false)
const loginType = ref<'scan' | 'sms' | 'account'>('scan')

const captcha = ref('')
const captchaText = ref('')

const imgCodeModalOpen = ref(false)
const imgCode = ref('')
const sendingSms = ref(false)

const countdown = ref(0)
let countdownTimer: ReturnType<typeof setInterval> | null = null

const selectUserOpen = ref(false)
const admins = ref<User[]>([])

const formRef = ref<FormInstance>()
const form = reactive<LoginParam & { smsCode?: string }>({
  username: '',
  password: '',
  phone: '',
  code: '',
  smsCode: '',
  remember: true
})

const phoneReg = /^1[3-9]\d{9}$/
const rules = reactive({
  username: [{ required: true, message: '请输入账号', type: 'string' }],
  password: [{ required: true, message: '请输入密码', type: 'string' }],
  code: [{ required: true, message: '请输入验证码', type: 'string' }],
  phone: [
    { required: true, message: '请输入手机号码', type: 'string' },
    { pattern: phoneReg, message: '手机号格式不正确', trigger: 'blur' }
  ],
  smsCode: [{ required: true, message: '请输入短信验证码', type: 'string' }]
})

const bgStyle = computed(() => {
  const bg = config.value?.loginBgImg
  if (!bg) return {}
  return { backgroundImage: `url(${bg})` }
})

function setLoginType(type: 'scan' | 'sms' | 'account') {
  loginType.value = type
}

function toggleScan() {
  loginType.value = loginType.value === 'scan' ? 'sms' : 'scan'
}

function stopCountdown() {
  if (countdownTimer) clearInterval(countdownTimer)
  countdownTimer = null
  countdown.value = 0
}

async function changeCaptcha() {
  try {
    const data = await getCaptcha()
    captcha.value = data.base64
    captchaText.value = data.text
  } catch (e: unknown) {
    message.error(e instanceof Error ? e.message : '获取验证码失败')
  }
}

function openImgCodeModal() {
  if (!form.phone) return message.error('请输入手机号码')
  imgCode.value = ''
  changeCaptcha()
  imgCodeModalOpen.value = true
}

async function sendSmsCode() {
  if (!imgCode.value) return message.error('请输入图形验证码')
  if (captchaText.value && imgCode.value.toLowerCase() !== captchaText.value.toLowerCase()) {
    return message.error('图形验证码不正确')
  }

  sendingSms.value = true
  try {
    await sendSmsCaptcha({ phone: form.phone })
    message.success('短信验证码发送成功，请注意查收')
    imgCodeModalOpen.value = false
    countdown.value = 30
    stopCountdown()
    countdown.value = 30
    countdownTimer = setInterval(() => {
      countdown.value -= 1
      if (countdown.value <= 0) stopCountdown()
    }, 1000)
  } catch (e: unknown) {
    message.error(e instanceof Error ? e.message : '发送失败')
  } finally {
    sendingSms.value = false
  }
}

async function goAfterLogin() {
  const from = typeof route.query.from === 'string' ? route.query.from : ''
  await navigateTo(from || '/')
}

async function submitAccount() {
  if (!formRef.value) return
  loading.value = true
  try {
    await formRef.value.validate()
    const msg = await login({
      username: form.username,
      password: form.password,
      code: String(form.code || '').toLowerCase(),
      remember: !!form.remember
    })
    message.success(msg || '登录成功')
    await goAfterLogin()
  } catch (e: unknown) {
    message.error(e instanceof Error ? e.message : '登录失败')
    changeCaptcha()
  } finally {
    loading.value = false
  }
}

async function submitSms() {
  if (!formRef.value) return
  loading.value = true
  try {
    await formRef.value.validate()
    const msg = await loginBySms({
      phone: form.phone,
      code: String(form.smsCode || '').toLowerCase(),
      tenantId: form.tenantId,
      remember: !!form.remember
    })

    if (msg === '请选择登录用户') {
      selectUserOpen.value = true
      admins.value = await listAdminsByPhoneAll({
        phone: form.phone,
        templateId: Number(TEMPLATE_ID)
      })
      return
    }

    message.success(msg || '登录成功')
    await goAfterLogin()
  } catch (e: unknown) {
    message.error(e instanceof Error ? e.message : '登录失败')
  } finally {
    loading.value = false
  }
}

async function selectUser(user: User) {
  form.tenantId = user.tenantId
  selectUserOpen.value = false
  await submitSms()
}

function onQrLoginSuccess(payload: QrCodeStatusResponse) {
  const accessToken = payload.accessToken || payload.access_token
  if (accessToken) setToken(String(accessToken), true)
  if (payload.tenantId && import.meta.client) localStorage.setItem('TenantId', String(payload.tenantId))
  if (import.meta.client && typeof payload.userInfo === 'object' && payload.userInfo && 'userId' in payload.userInfo) {
    const userId = (payload.userInfo as { userId?: unknown }).userId
    if (userId !== undefined && userId !== null) localStorage.setItem('UserId', String(userId))
  }
  message.success('扫码登录成功')
  goAfterLogin()
}

function onQrLoginError(error: string) {
  message.error(error || '扫码登录失败')
}

onMounted(async () => {
  try {
    config.value = await configWebsiteField({ lang: 'zh-CN' })
  } catch {
    // ignore config errors
  }
  changeCaptcha()

  if (typeof route.query.loginPhone === 'string') {
    form.phone = route.query.loginPhone
    loginType.value = 'sms'
  }
})

onUnmounted(() => {
  stopCountdown()
})
</script>

<style scoped>
.login-page {
  position: relative;
  min-height: 100vh;
  background: #111827;
  background-size: cover;
  background-position: center;
  padding: 48px 16px;
}
.overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.25);
}
.brand {
  position: absolute;
  top: 18px;
  left: 18px;
  display: flex;
  align-items: center;
  gap: 10px;
  z-index: 2;
}
.brand-logo {
  width: 28px;
  height: 28px;
  border-radius: 6px;
}
.brand-name {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: #fff;
}
.brand-title {
  position: absolute;
  top: 16%;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  color: #fff;
  font-size: 24px;
  font-weight: 600;
  text-align: center;
  padding: 0 12px;
}
.card {
  width: 390px;
  max-width: 100%;
  margin: 0 auto;
  background: #fff;
  padding: 0 28px 22px;
  border-radius: 10px;
  box-shadow: 0 10px 35px rgba(0, 0, 0, 0.25);
  position: relative;
  z-index: 2;
}
.card-header {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  gap: 12px;
  padding: 18px 0 6px;
}
.card-title {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
}
.tab {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  color: #374151;
}
.tab.active {
  color: #1677ff;
}
.switch {
  position: absolute;
  right: 0;
  top: 14px;
}
.input-group {
  display: flex;
  align-items: center;
}
.captcha-btn {
  width: 140px;
  height: 40px;
  margin-left: 10px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
}
.captcha-btn img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.row {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.copyright {
  z-index: 2;
  position: relative;
  margin-top: 28px;
  text-align: center;
  color: rgba(255, 255, 255, 0.85);
  font-size: 12px;
}
.sep {
  margin: 0 8px;
  opacity: 0.7;
}
.modal-row {
  margin-bottom: 16px;
}
.list-item {
  cursor: pointer;
}
</style>
