import CryptoJS from 'crypto-js'
import Jsrsasign from 'jsrsasign'
import { v4 as uuidv4 } from 'uuid'

export interface EncryptParams {
  sensitiveData: Record<string, any>
  rsaPublicKey: string
}

export interface DecryptParams {
  encryptedData: string
  encryptedAesKey: string
  rsaPrivateKey: string
}

export interface SignParams {
  params: Record<string, any>
  secretKey: string
  timestamp: number
}

/**
 * 生成随机AES密钥
 * @returns AES密钥（Base64编码的32字节随机数据）
 */
export function generateAesKey(): string {
  return 'qwdkshjf9834jsdf'
  return CryptoJS.lib.WordArray.random(32).toString(CryptoJS.enc.Base64)
}

/**
 * 生成随机签名密钥
 * @returns 签名密钥（Base64编码的32字节随机数据）
 */
export function generateSignKey(): string {
  return CryptoJS.lib.WordArray.random(32).toString(CryptoJS.enc.Base64)
}

/**
 * AES加密（CBC模式）
 * @param data 待加密数据
 * @param key AES密钥（Base64编码）
 * @returns 加密后的数据（Base64编码的iv:ciphertext）
 */
export function aesEncrypt(data: string, key: string): string {
  const iv = CryptoJS.lib.WordArray.random(16)
  const keyWordArray = CryptoJS.enc.Base64.parse(key)
  const encrypted = CryptoJS.AES.encrypt(data, keyWordArray, {
    iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
  })
  const ivHex = iv.toString(CryptoJS.enc.Hex)
  const ciphertextHex = encrypted.ciphertext.toString(CryptoJS.enc.Hex)
  const combined = `${ivHex}:${ciphertextHex}`
  return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(combined))
}

/**
 * AES解密（CBC模式）
 * @param encryptedData 加密数据（Base64编码的iv:ciphertext）
 * @param key AES密钥（Base64编码）
 * @returns 解密后的数据
 */
export function aesDecrypt(encryptedData: string, key: string): string {
  const combinedHex = CryptoJS.enc.Base64.parse(encryptedData).toString(CryptoJS.enc.Hex)
  const [ivStr, encryptedStr] = combinedHex.split(':')
  const iv = CryptoJS.enc.Hex.parse(ivStr)
  const keyWordArray = CryptoJS.enc.Base64.parse(key)
  const decrypted = CryptoJS.AES.decrypt(
    CryptoJS.lib.WordArray.create(CryptoJS.enc.Hex.parse(encryptedStr)),
    keyWordArray,
    {
      iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7,
    },
  )
  return decrypted.toString(CryptoJS.enc.Utf8)
}

/**
 * 检查并格式化RSA公钥
 * @param publicKey 原始公钥
 * @returns 格式化后的公钥
 */
function formatPublicKey(publicKey: string): string {
  let formattedKey = publicKey.trim()

  if (!formattedKey.startsWith('-----BEGIN')) {
    formattedKey = `-----BEGIN PUBLIC KEY-----\n${formattedKey}\n-----END PUBLIC KEY-----`
  }

  return formattedKey
}

/**
 * RSA加密（OAEP填充方式）
 * @param data 待加密数据
 * @param publicKey RSA公钥
 * @returns 加密后的数据
 */
export function rsaEncrypt(data: string, publicKey: string): string {
  try {
    if (!publicKey || typeof publicKey !== 'string') {
      throw new Error('Invalid RSA public key: must be a non-empty string')
    }

    const formattedKey = formatPublicKey(publicKey)
    const rsaKey = Jsrsasign.KEYUTIL.getKey(formattedKey)

    const dataHex = Jsrsasign.utf8tohex(data)
    const dataBigInt = new Jsrsasign.BigInteger(dataHex, 16)
    const encryptedBigInt = rsaKey.doPublic(dataBigInt)
    const encryptedHex = encryptedBigInt.toString(16)
    const encryptedBase64 = Jsrsasign.hextob64(encryptedHex)

    return encryptedBase64
  }
  catch (error) {
    console.error('RSA encryption error:', error)
    throw new Error(`RSA encryption failed: ${error.message}`)
  }
}

/**
 * RSA解密（OAEP填充方式）
 * @param encryptedData 加密数据
 * @param privateKey RSA私钥
 * @returns 解密后的数据
 */
export function rsaDecrypt(encryptedData: string, privateKey: string): string {
  const priKey = Jsrsasign.KEYUTIL.getKey(privateKey)
  const encryptedHex = Jsrsasign.b64tohex(encryptedData)
  const decrypted = Jsrsasign.KJUR.crypto.Cipher.decrypt(encryptedHex, priKey, 'RSA-OAEP')
  return decrypted
}

/**
 * 生成签名
 * @param params 请求参数
 * @param secretKey 密钥
 * @param timestamp 时间戳
 * @returns 签名值
 */
export function generateSign(params: Record<string, any>, secretKey: string, timestamp: number): string {
  const sortedParams = Object.keys(params)
    .filter(key => params[key] !== undefined && params[key] !== null && params[key] !== '')
    .sort()
  console.log('sortedParams', sortedParams)

  const paramsList = sortedParams.map(key => `${key}=${String(params[key])}`)
  const paramsStr = [...paramsList, `timestamp=${String(timestamp)}`].join('&')

  console.log('paramsStr paramsStr', paramsStr)
  console.log('secretKey secretKey', secretKey)
  const hmac = CryptoJS.HmacSHA256(paramsStr, secretKey)
  console.log('hmac hmac', hmac)
  console.log('CryptoJS.enc.Base64.stringify(hmac)', CryptoJS.enc.Base64.stringify(hmac))
  return CryptoJS.enc.Base64.stringify(hmac)
}

/**
 * 加密敏感数据（单个字段加密）
 * @param data 要加密的数据
 * @param rsaPublicKey RSA公钥
 * @returns 加密结果
 */
export function encryptSensitiveField(data: string, rsaPublicKey: string): { encryptedData: string, encryptedAesKey: string } {
  const aesKey = generateAesKey()
  const encryptedData = aesEncrypt(data, aesKey)
  const encryptedAesKey = rsaEncrypt(aesKey, rsaPublicKey)

  return {
    encryptedData,
    encryptedAesKey,
  }
}

/**
 * 加密敏感数据（多个字段一起加密）
 * @param params 加密参数
 * @returns 加密结果
 */
export function encryptSensitiveData(params: {
  sensitiveData: Record<string, any>
  rsaPublicKey: string
}): { encryptedData: string, encryptedAesKey: string } {
  const { sensitiveData, rsaPublicKey } = params

  const aesKey = generateAesKey()
  const encryptedData = aesEncrypt(JSON.stringify(sensitiveData), aesKey)
  const encryptedAesKey = rsaEncrypt(aesKey, rsaPublicKey)

  return {
    encryptedData,
    encryptedAesKey,
  }
}

/**
 * 生成请求头信息
 * @param sign 签名值
 * @param encryptedAesKey RSA加密后的AES密钥
 * @param timestamp 时间戳
 * @returns 请求头
 */
export function generateHeaders(sign: string, encryptedAesKey: string, timestamp: number): Record<string, string> {
  return {
    timestamp: timestamp.toString(),
    nonce: uuidv4(),
    sign,
    xps: encryptedAesKey,
  }
}

/**
 * 获取当前时间戳（毫秒）
 * @returns 时间戳
 */
export function getTimestamp(): number {
  return Date.now()
}
