import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
import { getScreenPublicKey, screenAutoLogin } from '@/api/login'
import { getToken, setToken } from '@/utils/auth'

/** URL 密文登录失败时展示给用户的提示 */
export const SCREEN_LOGIN_CIPHER_ERROR = '公钥不对'

/** URL uuid 免密登录失败时展示给用户的提示 */
export const SCREEN_LOGIN_UUID_ERROR = '免密失败，请联系管理员获取免登ID'

/** 同一会话内仅尝试一次免密登录，避免反复请求 */
let autoLoginState = null
let autoLoginPromise = null
let autoLoginUuid = null

export function isScreenAutoLoginEnabled() {
  return import.meta.env.VITE_SCREEN_AUTO_LOGIN === 'true'
}

export function resetScreenAutoLoginState() {
  autoLoginState = null
  autoLoginPromise = null
  autoLoginUuid = null
}

/** 从路由 query 读取 RSA 密文（?token=xxxx） */
export function getUrlScreenLoginCipher(query) {
  const raw = query?.token
  if (typeof raw !== 'string' || !raw.trim()) {
    return ''
  }
  try {
    return decodeURIComponent(raw.trim())
  } catch {
    return raw.trim()
  }
}

/** 从路由 query 读取免登 UUID（?uuid=xxxx） */
export function getUrlScreenLoginUuid(query) {
  const raw = query?.uuid
  if (typeof raw !== 'string' || !raw.trim()) {
    return ''
  }
  try {
    return decodeURIComponent(raw.trim())
  } catch {
    return raw.trim()
  }
}

/** 去掉 URL 中的 token，避免密文残留在地址栏 */
export function stripScreenLoginTokenQuery(query = {}) {
  const next = { ...query }
  delete next.token
  return next
}

/** 去掉 URL 中的 uuid */
export function stripScreenLoginUuidQuery(query = {}) {
  const next = { ...query }
  delete next.uuid
  return next
}

/**
 * 使用 URL 传入的 RSA 密文换取 JWT
 * @param {string} cipher
 * @returns {Promise<string>} JWT
 */
export async function tryScreenLoginWithCipher(cipher) {
  if (!cipher) {
    throw new Error(SCREEN_LOGIN_CIPHER_ERROR)
  }
  try {
    const loginRes = await screenAutoLogin(cipher)
    if (!loginRes?.token) {
      throw new Error(SCREEN_LOGIN_CIPHER_ERROR)
    }
    setToken(loginRes.token)
    autoLoginState = 'ok'
    return loginRes.token
  } catch {
    throw new Error(SCREEN_LOGIN_CIPHER_ERROR)
  }
}

/**
 * 获取公钥 → RSA 加密 URL 中的 UUID → 换取 JWT
 * @param {string} uuid
 * @returns {Promise<string>} JWT
 */
export async function tryScreenAutoLogin(uuid) {
  if (!uuid) {
    throw new Error(SCREEN_LOGIN_UUID_ERROR)
  }
  try {
    const keyRes = await getScreenPublicKey()
    const publicKey = keyRes.data?.publicKey
    if (!publicKey) {
      throw new Error(SCREEN_LOGIN_UUID_ERROR)
    }

    const encryptor = new JSEncrypt()
    encryptor.setPublicKey(publicKey)
    const cipher = encryptor.encrypt(uuid)
    if (!cipher) {
      throw new Error(SCREEN_LOGIN_UUID_ERROR)
    }

    const loginRes = await screenAutoLogin(cipher)
    if (!loginRes?.token) {
      throw new Error(SCREEN_LOGIN_UUID_ERROR)
    }
    setToken(loginRes.token)
    return loginRes.token
  } catch {
    throw new Error(SCREEN_LOGIN_UUID_ERROR)
  }
}

/**
 * 路由守卫用：URL 含 uuid 时尝试免密登录
 * @returns {Promise<{ attempted: boolean, ok: boolean }>}
 */
export async function ensureScreenAutoLogin(query) {
  if (getToken()) {
    return { attempted: false, ok: true }
  }
  if (!isScreenAutoLoginEnabled()) {
    return { attempted: false, ok: false }
  }

  const uuid = getUrlScreenLoginUuid(query)
  if (!uuid) {
    return { attempted: false, ok: false }
  }

  if (autoLoginState === 'fail' && autoLoginUuid === uuid) {
    return { attempted: true, ok: false }
  }
  if (autoLoginState === 'ok' && getToken()) {
    return { attempted: false, ok: true }
  }
  if (autoLoginState === 'pending' && autoLoginPromise && autoLoginUuid === uuid) {
    const ok = await autoLoginPromise
    return { attempted: true, ok }
  }

  autoLoginUuid = uuid
  autoLoginState = 'pending'
  autoLoginPromise = tryScreenAutoLogin(uuid)
    .then(() => {
      autoLoginState = 'ok'
      return true
    })
    .catch(() => {
      autoLoginState = 'fail'
      return false
    })

  const ok = await autoLoginPromise
  return { attempted: true, ok }
}
