// 纯 JS 精简版 AES-CBC-Pkcs7
function toBytes(str) {
  const utf8 = [];
  for (let i = 0; i < str.length; i++) {
    let charcode = str.charCodeAt(i);
    if (charcode < 0x80) utf8.push(charcode);
    else if (charcode < 0x800) {
      utf8.push(0xc0 | (charcode >> 6), 0x80 | (charcode & 0x3f));
    } else if (charcode < 0xd800 || charcode >= 0xe000) {
      utf8.push(0xe0 | (charcode >> 12), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f));
    } else {
      i++;
      charcode = 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
      utf8.push(0xf0 | (charcode >> 18), 0x80 | ((charcode >> 12) & 0x3f), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f));
    }
  }
  return utf8;
}
function fromBytes(bytes) {
  let out = '', i = 0, c = 0;
  while (i < bytes.length) {
    c = bytes[i++];
    if (c < 128) out += String.fromCharCode(c);
    else if (c > 191 && c < 224) out += String.fromCharCode(((c & 31) << 6) | (bytes[i++] & 63));
    else if (c > 223 && c < 240) out += String.fromCharCode(((c & 15) << 12) | ((bytes[i++] & 63) << 6) | (bytes[i++] & 63));
    else {
      let u = (((c & 7) << 18) | ((bytes[i++] & 63) << 12) | ((bytes[i++] & 63) << 6) | (bytes[i++] & 63)) - 0x10000;
      out += String.fromCharCode(0xd800 + (u >> 10), 0xdc00 + (u & 1023));
    }
  }
  return out;
}
const b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
function bytesToBase64(bytes) {
  let str = '', i = 0;
  while (i < bytes.length) {
    let c1 = bytes[i++], c2 = bytes[i++], c3 = bytes[i++];
    let e1 = c1 >> 2, e2 = ((c1 & 3) << 4) | (c2 >> 4), e3 = ((c2 & 15) << 2) | (c3 >> 6), e4 = c3 & 63;
    if (isNaN(c2)) e3 = e4 = 64;
    else if (isNaN(c3)) e4 = 64;
    str += b64chars.charAt(e1) + b64chars.charAt(e2) + b64chars.charAt(e3) + b64chars.charAt(e4);
  }
  return str;
}

function base64ToBytes(str) {
  let output = [], i = 0;
  str = str.replace(/[^A-Za-z0-9\+\/\=]/g, '');
  while (i < str.length) {
    let e1 = b64chars.indexOf(str.charAt(i++)), e2 = b64chars.indexOf(str.charAt(i++)), e3 = b64chars.indexOf(str.charAt(i++)), e4 = b64chars.indexOf(str.charAt(i++));
    let c1 = (e1 << 2) | (e2 >> 4), c2 = ((e2 & 15) << 4) | (e3 >> 2), c3 = ((e3 & 3) << 6) | e4;
    output.push(c1);
    if (e3 !== 64) output.push(c2);
    if (e4 !== 64) output.push(c3);
  }
  return output;
}
function pkcs7Pad(data) {
  const blockSize = 16; // AES块大小为16字节
  const pad = blockSize - (data.length % blockSize);
  return data.concat(Array(pad).fill(pad));
}

function pkcs7Unpad(data) {
  const blockSize = 16; // 确保这里也定义blockSize
  const pad = data[data.length - 1];
  if (pad > 0 && pad <= blockSize) {
    for (let i = data.length - pad; i < data.length; i++) {
      if (data[i] !== pad) return data; // 如果填充无效，则返回原始数据
    }
    return data.slice(0, data.length - pad);
  }
  return data;
}
function xorBlock(a, b) {
  const out = [];
  for (let i = 0; i < a.length; i++) out[i] = a[i] ^ b[i];
  return out;
}
function aesBlockEncrypt(block, key) {
  // 这里只做简单异或模拟，实际应用请用官方库
  return xorBlock(block, key);
}
function aesBlockDecrypt(block, key) {
  // 这里只做简单异或模拟，实际应用请用官方库
  return xorBlock(block, key);
}
function aesCbcEncrypt(plainBytes, keyBytes, ivBytes) {
  let padded = pkcs7Pad(plainBytes); // 应用PKCS#7填充
  let blocks = [], prev = ivBytes;
  for (let i = 0; i < padded.length; i += 16) {
    let block = padded.slice(i, i + 16);
    let xored = xorBlock(block, prev);
    let encrypted = aesBlockEncrypt(xored, keyBytes);
    blocks = blocks.concat(encrypted);
    prev = encrypted;
  }
  return blocks; // 返回完整的加密块
}

function aesCbcDecrypt(cipherBytes, keyBytes, ivBytes) {
  let blocks = [], prev = ivBytes;
  for (let i = 0; i < cipherBytes.length; i += 16) {
    let block = cipherBytes.slice(i, i + 16);
    let decrypted = aesBlockDecrypt(block, keyBytes);
    let xored = xorBlock(decrypted, prev);
    blocks = blocks.concat(xored);
    prev = block;
  }
  return pkcs7Unpad(blocks); // 移除PKCS#7填充
}
const CryptoJS = {};
CryptoJS.enc = {
  Utf8: {
    parse: toBytes,
    stringify: fromBytes
  },
  Base64: {
    parse: base64ToBytes,
    stringify: bytesToBase64
  }
};
CryptoJS.mode = { CBC: {} };
CryptoJS.pad = {
  Pkcs7: {
    pad: pkcs7Pad,
    unpad: pkcs7Unpad
  }
};
CryptoJS.AES = {
  encrypt: function (data, key, options) {
    let bytes = typeof data === 'string' ? toBytes(data) : data;
    let k = typeof key === 'string' ? toBytes(key) : Array.from(key);
    let iv = typeof options.iv === 'string' ? toBytes(options.iv) : Array.from(options.iv);
    let encryptedBlocks = aesCbcEncrypt(bytes, k, iv);
    return {
      toString: function () {
        return CryptoJS.enc.Base64.stringify(encryptedBlocks); // 使用标准方法转换为Base64
      }
    };
  },
  decrypt: function (ciphertext, key, options) {
    let cipherBytes = typeof ciphertext === 'string' ? base64ToBytes(ciphertext) : ciphertext;
    let k = typeof key === 'string' ? toBytes(key) : Array.from(key);
    let iv = typeof options.iv === 'string' ? toBytes(options.iv) : Array.from(options.iv);
    let decrypted = aesCbcDecrypt(cipherBytes, k, iv);
    return {
      toString: function (enc) {
        if (enc && enc === CryptoJS.enc.Utf8) {
          return CryptoJS.enc.Utf8.stringify(decrypted); // 转换回原始字符串
        }
        return decrypted;
      }
    };
  }
};

export default CryptoJS;