/**
 * 加密解密工具类
 * 提供数据加密、解密、哈希等安全功能
 */

import { createLogger } from './logger.js'

const logger = createLogger('Crypto')

/**
 * Base64 编码解码
 */
export const base64 = {
  /**
   * Base64 编码
   * @param {string} str - 要编码的字符串
   * @returns {string} 编码后的字符串
   */
  encode(str) {
    try {
      // 在小程序环境中使用内置方法
      if (typeof wx !== 'undefined') {
        return wx.arrayBufferToBase64(
          new TextEncoder().encode(str).buffer
        )
      }
      
      // 在其他环境中使用 btoa
      if (typeof btoa !== 'undefined') {
        return btoa(unescape(encodeURIComponent(str)))
      }
      
      // 手动实现 Base64 编码
      return this._manualEncode(str)
    } catch (error) {
      logger.error('Base64 encode failed', { str }, error)
      return ''
    }
  },

  /**
   * Base64 解码
   * @param {string} str - 要解码的字符串
   * @returns {string} 解码后的字符串
   */
  decode(str) {
    try {
      // 在小程序环境中使用内置方法
      if (typeof wx !== 'undefined') {
        const buffer = wx.base64ToArrayBuffer(str)
        return new TextDecoder().decode(buffer)
      }
      
      // 在其他环境中使用 atob
      if (typeof atob !== 'undefined') {
        return decodeURIComponent(escape(atob(str)))
      }
      
      // 手动实现 Base64 解码
      return this._manualDecode(str)
    } catch (error) {
      logger.error('Base64 decode failed', { str }, error)
      return ''
    }
  },

  /**
   * 手动 Base64 编码实现
   * @private
   */
  _manualEncode(str) {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    let result = ''
    let i = 0
    
    while (i < str.length) {
      const a = str.charCodeAt(i++)
      const b = i < str.length ? str.charCodeAt(i++) : 0
      const c = i < str.length ? str.charCodeAt(i++) : 0
      
      const bitmap = (a << 16) | (b << 8) | c
      
      result += chars.charAt((bitmap >> 18) & 63)
      result += chars.charAt((bitmap >> 12) & 63)
      result += i - 2 < str.length ? chars.charAt((bitmap >> 6) & 63) : '='
      result += i - 1 < str.length ? chars.charAt(bitmap & 63) : '='
    }
    
    return result
  },

  /**
   * 手动 Base64 解码实现
   * @private
   */
  _manualDecode(str) {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    let result = ''
    let i = 0
    
    str = str.replace(/[^A-Za-z0-9+/]/g, '')
    
    while (i < str.length) {
      const encoded1 = chars.indexOf(str.charAt(i++))
      const encoded2 = chars.indexOf(str.charAt(i++))
      const encoded3 = chars.indexOf(str.charAt(i++))
      const encoded4 = chars.indexOf(str.charAt(i++))
      
      const bitmap = (encoded1 << 18) | (encoded2 << 12) | (encoded3 << 6) | encoded4
      
      result += String.fromCharCode((bitmap >> 16) & 255)
      if (encoded3 !== 64) result += String.fromCharCode((bitmap >> 8) & 255)
      if (encoded4 !== 64) result += String.fromCharCode(bitmap & 255)
    }
    
    return result
  }
}

/**
 * MD5 哈希算法
 */
export const md5 = {
  /**
   * 计算 MD5 哈希值
   * @param {string} str - 要计算哈希的字符串
   * @returns {string} MD5 哈希值
   */
  hash(str) {
    try {
      return this._md5(str)
    } catch (error) {
      logger.error('MD5 hash failed', { str }, error)
      return ''
    }
  },

  /**
   * MD5 算法实现
   * @private
   */
  _md5(str) {
    const rotateLeft = (value, amount) => {
      const lbits = value << amount
      const rbits = value >>> (32 - amount)
      return lbits | rbits
    }

    const addUnsigned = (x, y) => {
      const x4 = x & 0x40000000
      const y4 = y & 0x40000000
      const x8 = x & 0x80000000
      const y8 = y & 0x80000000
      const result = (x & 0x3FFFFFFF) + (y & 0x3FFFFFFF)
      
      if (x4 & y4) {
        return result ^ 0x80000000 ^ x8 ^ y8
      }
      if (x4 | y4) {
        if (result & 0x40000000) {
          return result ^ 0xC0000000 ^ x8 ^ y8
        } else {
          return result ^ 0x40000000 ^ x8 ^ y8
        }
      } else {
        return result ^ x8 ^ y8
      }
    }

    const f = (x, y, z) => (x & y) | (~x & z)
    const g = (x, y, z) => (x & z) | (y & ~z)
    const h = (x, y, z) => x ^ y ^ z
    const i = (x, y, z) => y ^ (x | ~z)

    const ff = (a, b, c, d, x, s, ac) => {
      a = addUnsigned(a, addUnsigned(addUnsigned(f(b, c, d), x), ac))
      return addUnsigned(rotateLeft(a, s), b)
    }

    const gg = (a, b, c, d, x, s, ac) => {
      a = addUnsigned(a, addUnsigned(addUnsigned(g(b, c, d), x), ac))
      return addUnsigned(rotateLeft(a, s), b)
    }

    const hh = (a, b, c, d, x, s, ac) => {
      a = addUnsigned(a, addUnsigned(addUnsigned(h(b, c, d), x), ac))
      return addUnsigned(rotateLeft(a, s), b)
    }

    const ii = (a, b, c, d, x, s, ac) => {
      a = addUnsigned(a, addUnsigned(addUnsigned(i(b, c, d), x), ac))
      return addUnsigned(rotateLeft(a, s), b)
    }

    const convertToWordArray = (str) => {
      let wordArray = []
      let messageLength = str.length
      let numberOfWords = (((messageLength + 8) - ((messageLength + 8) % 64)) / 64 + 1) * 16
      
      for (let i = 0; i < numberOfWords; i++) {
        wordArray[i] = 0
      }
      
      for (let i = 0; i < messageLength; i++) {
        wordArray[i >>> 2] |= (str.charCodeAt(i) & 0xFF) << (24 - (i % 4) * 8)
      }
      
      wordArray[messageLength >>> 2] |= 0x80 << (24 - (messageLength % 4) * 8)
      wordArray[numberOfWords - 2] = messageLength << 3
      wordArray[numberOfWords - 1] = messageLength >>> 29
      
      return wordArray
    }

    const wordToHex = (value) => {
      let result = ''
      for (let i = 0; i <= 3; i++) {
        const byte = (value >>> (i * 8)) & 255
        result += ('0' + byte.toString(16)).slice(-2)
      }
      return result
    }

    const x = convertToWordArray(str)
    let a = 0x67452301
    let b = 0xEFCDAB89
    let c = 0x98BADCFE
    let d = 0x10325476

    for (let k = 0; k < x.length; k += 16) {
      const AA = a
      const BB = b
      const CC = c
      const DD = d

      a = ff(a, b, c, d, x[k], 7, 0xD76AA478)
      d = ff(d, a, b, c, x[k + 1], 12, 0xE8C7B756)
      c = ff(c, d, a, b, x[k + 2], 17, 0x242070DB)
      b = ff(b, c, d, a, x[k + 3], 22, 0xC1BDCEEE)
      a = ff(a, b, c, d, x[k + 4], 7, 0xF57C0FAF)
      d = ff(d, a, b, c, x[k + 5], 12, 0x4787C62A)
      c = ff(c, d, a, b, x[k + 6], 17, 0xA8304613)
      b = ff(b, c, d, a, x[k + 7], 22, 0xFD469501)
      a = ff(a, b, c, d, x[k + 8], 7, 0x698098D8)
      d = ff(d, a, b, c, x[k + 9], 12, 0x8B44F7AF)
      c = ff(c, d, a, b, x[k + 10], 17, 0xFFFF5BB1)
      b = ff(b, c, d, a, x[k + 11], 22, 0x895CD7BE)
      a = ff(a, b, c, d, x[k + 12], 7, 0x6B901122)
      d = ff(d, a, b, c, x[k + 13], 12, 0xFD987193)
      c = ff(c, d, a, b, x[k + 14], 17, 0xA679438E)
      b = ff(b, c, d, a, x[k + 15], 22, 0x49B40821)

      a = gg(a, b, c, d, x[k + 1], 5, 0xF61E2562)
      d = gg(d, a, b, c, x[k + 6], 9, 0xC040B340)
      c = gg(c, d, a, b, x[k + 11], 14, 0x265E5A51)
      b = gg(b, c, d, a, x[k], 20, 0xE9B6C7AA)
      a = gg(a, b, c, d, x[k + 5], 5, 0xD62F105D)
      d = gg(d, a, b, c, x[k + 10], 9, 0x2441453)
      c = gg(c, d, a, b, x[k + 15], 14, 0xD8A1E681)
      b = gg(b, c, d, a, x[k + 4], 20, 0xE7D3FBC8)
      a = gg(a, b, c, d, x[k + 9], 5, 0x21E1CDE6)
      d = gg(d, a, b, c, x[k + 14], 9, 0xC33707D6)
      c = gg(c, d, a, b, x[k + 3], 14, 0xF4D50D87)
      b = gg(b, c, d, a, x[k + 8], 20, 0x455A14ED)
      a = gg(a, b, c, d, x[k + 13], 5, 0xA9E3E905)
      d = gg(d, a, b, c, x[k + 2], 9, 0xFCEFA3F8)
      c = gg(c, d, a, b, x[k + 7], 14, 0x676F02D9)
      b = gg(b, c, d, a, x[k + 12], 20, 0x8D2A4C8A)

      a = hh(a, b, c, d, x[k + 5], 4, 0xFFFA3942)
      d = hh(d, a, b, c, x[k + 8], 11, 0x8771F681)
      c = hh(c, d, a, b, x[k + 11], 16, 0x6D9D6122)
      b = hh(b, c, d, a, x[k + 14], 23, 0xFDE5380C)
      a = hh(a, b, c, d, x[k + 1], 4, 0xA4BEEA44)
      d = hh(d, a, b, c, x[k + 4], 11, 0x4BDECFA9)
      c = hh(c, d, a, b, x[k + 7], 16, 0xF6BB4B60)
      b = hh(b, c, d, a, x[k + 10], 23, 0xBEBFBC70)
      a = hh(a, b, c, d, x[k + 13], 4, 0x289B7EC6)
      d = hh(d, a, b, c, x[k], 11, 0xEAA127FA)
      c = hh(c, d, a, b, x[k + 3], 16, 0xD4EF3085)
      b = hh(b, c, d, a, x[k + 6], 23, 0x4881D05)
      a = hh(a, b, c, d, x[k + 9], 4, 0xD9D4D039)
      d = hh(d, a, b, c, x[k + 12], 11, 0xE6DB99E5)
      c = hh(c, d, a, b, x[k + 15], 16, 0x1FA27CF8)
      b = hh(b, c, d, a, x[k + 2], 23, 0xC4AC5665)

      a = ii(a, b, c, d, x[k], 6, 0xF4292244)
      d = ii(d, a, b, c, x[k + 7], 10, 0x432AFF97)
      c = ii(c, d, a, b, x[k + 14], 15, 0xAB9423A7)
      b = ii(b, c, d, a, x[k + 5], 21, 0xFC93A039)
      a = ii(a, b, c, d, x[k + 12], 6, 0x655B59C3)
      d = ii(d, a, b, c, x[k + 3], 10, 0x8F0CCC92)
      c = ii(c, d, a, b, x[k + 10], 15, 0xFFEFF47D)
      b = ii(b, c, d, a, x[k + 1], 21, 0x85845DD1)
      a = ii(a, b, c, d, x[k + 8], 6, 0x6FA87E4F)
      d = ii(d, a, b, c, x[k + 15], 10, 0xFE2CE6E0)
      c = ii(c, d, a, b, x[k + 6], 15, 0xA3014314)
      b = ii(b, c, d, a, x[k + 13], 21, 0x4E0811A1)
      a = ii(a, b, c, d, x[k + 4], 6, 0xF7537E82)
      d = ii(d, a, b, c, x[k + 11], 10, 0xBD3AF235)
      c = ii(c, d, a, b, x[k + 2], 15, 0x2AD7D2BB)
      b = ii(b, c, d, a, x[k + 9], 21, 0xEB86D391)

      a = addUnsigned(a, AA)
      b = addUnsigned(b, BB)
      c = addUnsigned(c, CC)
      d = addUnsigned(d, DD)
    }

    return (wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d)).toLowerCase()
  }
}

/**
 * SHA256 哈希算法
 */
export const sha256 = {
  /**
   * 计算 SHA256 哈希值
   * @param {string} str - 要计算哈希的字符串
   * @returns {string} SHA256 哈希值
   */
  hash(str) {
    try {
      return this._sha256(str)
    } catch (error) {
      logger.error('SHA256 hash failed', { str }, error)
      return ''
    }
  },

  /**
   * SHA256 算法实现
   * @private
   */
  _sha256(str) {
    const K = [
      0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
      0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
      0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
      0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
      0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
      0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
      0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
      0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
    ]

    const rotr = (n, x) => (x >>> n) | (x << (32 - n))
    const ch = (x, y, z) => (x & y) ^ (~x & z)
    const maj = (x, y, z) => (x & y) ^ (x & z) ^ (y & z)
    const sigma0 = (x) => rotr(2, x) ^ rotr(13, x) ^ rotr(22, x)
    const sigma1 = (x) => rotr(6, x) ^ rotr(11, x) ^ rotr(25, x)
    const gamma0 = (x) => rotr(7, x) ^ rotr(18, x) ^ (x >>> 3)
    const gamma1 = (x) => rotr(17, x) ^ rotr(19, x) ^ (x >>> 10)

    const utf8Encode = (str) => {
      return unescape(encodeURIComponent(str))
    }

    const stringToBytes = (str) => {
      const bytes = []
      for (let i = 0; i < str.length; i++) {
        bytes.push(str.charCodeAt(i))
      }
      return bytes
    }

    const bytesToWords = (bytes) => {
      const words = []
      for (let i = 0, b = 0; i < bytes.length; i++, b += 8) {
        words[b >>> 5] |= bytes[i] << (24 - b % 32)
      }
      return words
    }

    const wordsToHex = (words) => {
      const hex = []
      for (let i = 0; i < words.length * 32; i += 8) {
        hex.push(((words[i >>> 5] >>> (24 - i % 32)) & 0xFF).toString(16).padStart(2, '0'))
      }
      return hex.join('')
    }

    // 预处理
    const message = utf8Encode(str)
    const messageBytes = stringToBytes(message)
    const messageBits = messageBytes.length * 8
    
    // 添加填充
    messageBytes.push(0x80)
    while (messageBytes.length % 64 !== 56) {
      messageBytes.push(0x00)
    }
    
    // 添加长度
    for (let i = 7; i >= 0; i--) {
      messageBytes.push((messageBits >>> (i * 8)) & 0xFF)
    }

    const words = bytesToWords(messageBytes)

    // 初始哈希值
    let h0 = 0x6a09e667
    let h1 = 0xbb67ae85
    let h2 = 0x3c6ef372
    let h3 = 0xa54ff53a
    let h4 = 0x510e527f
    let h5 = 0x9b05688c
    let h6 = 0x1f83d9ab
    let h7 = 0x5be0cd19

    // 处理消息块
    for (let i = 0; i < words.length; i += 16) {
      const w = words.slice(i, i + 16)
      
      // 扩展消息调度
      for (let j = 16; j < 64; j++) {
        w[j] = (gamma1(w[j - 2]) + w[j - 7] + gamma0(w[j - 15]) + w[j - 16]) >>> 0
      }

      let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7

      // 主循环
      for (let j = 0; j < 64; j++) {
        const t1 = (h + sigma1(e) + ch(e, f, g) + K[j] + w[j]) >>> 0
        const t2 = (sigma0(a) + maj(a, b, c)) >>> 0
        
        h = g
        g = f
        f = e
        e = (d + t1) >>> 0
        d = c
        c = b
        b = a
        a = (t1 + t2) >>> 0
      }

      // 更新哈希值
      h0 = (h0 + a) >>> 0
      h1 = (h1 + b) >>> 0
      h2 = (h2 + c) >>> 0
      h3 = (h3 + d) >>> 0
      h4 = (h4 + e) >>> 0
      h5 = (h5 + f) >>> 0
      h6 = (h6 + g) >>> 0
      h7 = (h7 + h) >>> 0
    }

    return wordsToHex([h0, h1, h2, h3, h4, h5, h6, h7])
  }
}

/**
 * 简单的对称加密（仅用于演示，不建议用于生产环境）
 */
export const simpleEncrypt = {
  /**
   * 简单加密
   * @param {string} text - 要加密的文本
   * @param {string} key - 加密密钥
   * @returns {string} 加密后的文本
   */
  encrypt(text, key) {
    try {
      let result = ''
      const keyLength = key.length
      
      for (let i = 0; i < text.length; i++) {
        const textChar = text.charCodeAt(i)
        const keyChar = key.charCodeAt(i % keyLength)
        const encryptedChar = textChar ^ keyChar
        result += String.fromCharCode(encryptedChar)
      }
      
      return base64.encode(result)
    } catch (error) {
      logger.error('Simple encrypt failed', { text, key }, error)
      return ''
    }
  },

  /**
   * 简单解密
   * @param {string} encryptedText - 要解密的文本
   * @param {string} key - 解密密钥
   * @returns {string} 解密后的文本
   */
  decrypt(encryptedText, key) {
    try {
      const decodedText = base64.decode(encryptedText)
      let result = ''
      const keyLength = key.length
      
      for (let i = 0; i < decodedText.length; i++) {
        const encryptedChar = decodedText.charCodeAt(i)
        const keyChar = key.charCodeAt(i % keyLength)
        const decryptedChar = encryptedChar ^ keyChar
        result += String.fromCharCode(decryptedChar)
      }
      
      return result
    } catch (error) {
      logger.error('Simple decrypt failed', { encryptedText, key }, error)
      return ''
    }
  }
}

/**
 * 随机数生成器
 */
export const random = {
  /**
   * 生成随机字符串
   * @param {number} length - 字符串长度
   * @param {string} chars - 字符集
   * @returns {string} 随机字符串
   */
  string(length = 16, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
    let result = ''
    for (let i = 0; i < length; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length))
    }
    return result
  },

  /**
   * 生成随机数字
   * @param {number} min - 最小值
   * @param {number} max - 最大值
   * @returns {number} 随机数字
   */
  number(min = 0, max = 100) {
    return Math.floor(Math.random() * (max - min + 1)) + min
  },

  /**
   * 生成UUID
   * @returns {string} UUID
   */
  uuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
      const r = Math.random() * 16 | 0
      const v = c === 'x' ? r : (r & 0x3 | 0x8)
      return v.toString(16)
    })
  },

  /**
   * 生成随机盐值
   * @param {number} length - 盐值长度
   * @returns {string} 盐值
   */
  salt(length = 32) {
    return this.string(length, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*')
  }
}

/**
 * 密码工具
 */
export const password = {
  /**
   * 生成密码哈希
   * @param {string} password - 原始密码
   * @param {string} salt - 盐值
   * @returns {string} 密码哈希
   */
  hash(password, salt = null) {
    try {
      const usedSalt = salt || random.salt()
      const combined = password + usedSalt
      const hashed = sha256.hash(combined)
      return `${hashed}:${usedSalt}`
    } catch (error) {
      logger.error('Password hash failed', { password, salt }, error)
      return ''
    }
  },

  /**
   * 验证密码
   * @param {string} password - 原始密码
   * @param {string} hashedPassword - 哈希密码
   * @returns {boolean} 是否匹配
   */
  verify(password, hashedPassword) {
    try {
      const [hash, salt] = hashedPassword.split(':')
      if (!hash || !salt) {
        return false
      }
      
      const newHash = this.hash(password, salt)
      return newHash === hashedPassword
    } catch (error) {
      logger.error('Password verify failed', { password, hashedPassword }, error)
      return false
    }
  },

  /**
   * 生成强密码
   * @param {number} length - 密码长度
   * @returns {string} 强密码
   */
  generate(length = 12) {
    const lowercase = 'abcdefghijklmnopqrstuvwxyz'
    const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    const numbers = '0123456789'
    const symbols = '!@#$%^&*()_+-=[]{}|;:,.<>?'
    
    let password = ''
    let chars = lowercase + uppercase + numbers + symbols
    
    // 确保包含各种字符类型
    password += lowercase[Math.floor(Math.random() * lowercase.length)]
    password += uppercase[Math.floor(Math.random() * uppercase.length)]
    password += numbers[Math.floor(Math.random() * numbers.length)]
    password += symbols[Math.floor(Math.random() * symbols.length)]
    
    // 填充剩余长度
    for (let i = 4; i < length; i++) {
      password += chars[Math.floor(Math.random() * chars.length)]
    }
    
    // 打乱密码字符顺序
    return password.split('').sort(() => Math.random() - 0.5).join('')
  },

  /**
   * 检查密码强度
   * @param {string} password - 密码
   * @returns {Object} 强度信息
   */
  strength(password) {
    const checks = {
      length: password.length >= 8,
      lowercase: /[a-z]/.test(password),
      uppercase: /[A-Z]/.test(password),
      numbers: /\d/.test(password),
      symbols: /[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]/.test(password)
    }
    
    const score = Object.values(checks).filter(Boolean).length
    
    let level = 'weak'
    if (score >= 4) level = 'strong'
    else if (score >= 3) level = 'medium'
    
    return {
      score,
      level,
      checks,
      suggestions: this._getPasswordSuggestions(checks)
    }
  },

  /**
   * 获取密码建议
   * @private
   */
  _getPasswordSuggestions(checks) {
    const suggestions = []
    
    if (!checks.length) suggestions.push('密码长度至少8位')
    if (!checks.lowercase) suggestions.push('包含小写字母')
    if (!checks.uppercase) suggestions.push('包含大写字母')
    if (!checks.numbers) suggestions.push('包含数字')
    if (!checks.symbols) suggestions.push('包含特殊字符')
    
    return suggestions
  }
}

// 导出所有加密工具
export default {
  base64,
  md5,
  sha256,
  simpleEncrypt,
  random,
  password
}