import 'dart:convert';
import 'dart:typed_data';

import 'package:pointycastle/export.dart';

class AesDecrypt {
  static const String _cn = 'i0.a';

  static const List<int> _obf = <int>[
    0xED,
    0x7A,
    0x7F,
    0x3F,
    0x9E,
    0x6E,
    0xE7,
    0xF9,
    0x06,
    0xA0,
    0xA8,
    0xE4,
    0x16,
    0xE5,
    0x69,
    0x70,
  ];

  /// Java String.hashCode() 等价实现（32-bit signed）
  static int javaStringHashCode(String str) {
    int h = 0;
    for (int i = 0; i < str.length; i++) {
      h = _toSigned32(h * 31 + str.codeUnitAt(i));
    }
    return h;
  }

  static int _toSigned32(int value) {
    value &= 0xFFFFFFFF;
    if ((value & 0x80000000) != 0) {
      return value - 0x100000000;
    }
    return value;
  }

  static int _unsignedRightShift32(int value, int shift) {
    return (value & 0xFFFFFFFF) >> shift;
  }

  static Uint8List deriveKeyBytes16() {
    final int seed = _toSigned32(javaStringHashCode(_cn) ^ 0x5f3759df);

    final Uint8List keyBytes = Uint8List(16);

    for (int i = 0; i < 16; i++) {
      final int shift = (i & 3) * 8;
      final int shifted = _unsignedRightShift32(seed, shift);
      final int mask = (((shifted & 0xff) ^ ((i * 17 + 31) & 0xff)) & 0xff);
      keyBytes[i] = (_obf[i] ^ mask) & 0xff;
    }

    return keyBytes;
  }

  static Uint8List _aesEcbPkcs7(bool forEncryption, Uint8List input) {
    final key = deriveKeyBytes16();

    final cipher = PaddedBlockCipherImpl(
      PKCS7Padding(),
      ECBBlockCipher(AESEngine()),
    );

    cipher.init(
      forEncryption,
      PaddedBlockCipherParameters<CipherParameters, CipherParameters>(
        KeyParameter(key),
        null,
      ),
    );

    return cipher.process(input);
  }

  /// 对应 JS / Java encrypt(String) -> Base64.NO_WRAP
  static String encrypt(String plainText) {
    try {
      final Uint8List input = Uint8List.fromList(utf8.encode(plainText));
      final Uint8List encrypted = _aesEcbPkcs7(true, input);
      return base64.encode(encrypted);
    } catch (_) {
      return '';
    }
  }

  /// 对应 JS / Java decrypt(String base64Encrypted) -> UTF-8
  static String? decrypt(String base64Encrypted) {
    try {
      final Uint8List encrypted = Uint8List.fromList(
        base64.decode(base64Encrypted),
      );
      final Uint8List decrypted = _aesEcbPkcs7(false, encrypted);
      final String text = utf8.decode(decrypted, allowMalformed: false);
      return text.isNotEmpty ? text : null;
    } catch (_) {
      return null;
    }
  }

  // =========================
  // 新增：支持自定义 key / iv
  // AES/CBC/PKCS7
  // =========================

  static Uint8List _normalizeKey(String key) {
    final Uint8List keyBytes = Uint8List.fromList(utf8.encode(key));

    if (keyBytes.length != 16 &&
        keyBytes.length != 24 &&
        keyBytes.length != 32) {
      throw ArgumentError('AES key length must be 16/24/32 bytes.');
    }
    return keyBytes;
  }

  static Uint8List _normalizeIv(String iv) {
    final Uint8List ivBytes = Uint8List.fromList(utf8.encode(iv));
    if (ivBytes.length != 16) {
      throw ArgumentError('AES CBC iv length must be 16 bytes.');
    }
    return ivBytes;
  }

  static Uint8List _aesCbcPkcs7(
    bool forEncryption,
    Uint8List input,
    Uint8List key,
    Uint8List iv,
  ) {
    final cipher = PaddedBlockCipherImpl(
      PKCS7Padding(),
      CBCBlockCipher(AESEngine()),
    );

    cipher.init(
      forEncryption,
      PaddedBlockCipherParameters<CipherParameters, CipherParameters>(
        ParametersWithIV<KeyParameter>(KeyParameter(key), iv),
        null,
      ),
    );

    return cipher.process(input);
  }

  /// 使用传入 key / iv 加密，返回 Base64
  ///
  /// key 长度必须为 16 / 24 / 32 字节
  /// iv 长度必须为 16 字节
  static String encryptWithKeyIv(
    String plainText, {
    required String key,
    required String iv,
  }) {
    try {
      final Uint8List input = Uint8List.fromList(utf8.encode(plainText));
      final Uint8List keyBytes = _normalizeKey(key);
      final Uint8List ivBytes = _normalizeIv(iv);

      final Uint8List encrypted = _aesCbcPkcs7(true, input, keyBytes, ivBytes);
      return base64.encode(encrypted);
    } catch (_) {
      return '';
    }
  }

  /// 使用传入 key / iv 解密 Base64 密文，返回 UTF-8 字符串
  ///
  /// key 长度必须为 16 / 24 / 32 字节
  /// iv 长度必须为 16 字节
  static String? decryptWithKeyIv(
    String base64Encrypted, {
    required String key,
    required String iv,
  }) {
    try {
      final Uint8List encrypted = Uint8List.fromList(
        base64.decode(base64Encrypted),
      );
      final Uint8List keyBytes = _normalizeKey(key);
      final Uint8List ivBytes = _normalizeIv(iv);

      final Uint8List decrypted = _aesCbcPkcs7(
        false,
        encrypted,
        keyBytes,
        ivBytes,
      );
      final String text = utf8.decode(decrypted, allowMalformed: false);
      return text.isNotEmpty ? text : null;
    } catch (_) {
      return null;
    }
  }

  // =========================
  // 可选新增：支持直接传 Uint8List
  // =========================

  static Uint8List encryptBytesWithKeyIv(
    Uint8List plainBytes, {
    required Uint8List key,
    required Uint8List iv,
  }) {
    if (key.length != 16 && key.length != 24 && key.length != 32) {
      throw ArgumentError('AES key length must be 16/24/32 bytes.');
    }
    if (iv.length != 16) {
      throw ArgumentError('AES CBC iv length must be 16 bytes.');
    }
    return _aesCbcPkcs7(true, plainBytes, key, iv);
  }

  static Uint8List decryptBytesWithKeyIv(
    Uint8List encryptedBytes, {
    required Uint8List key,
    required Uint8List iv,
  }) {
    if (key.length != 16 && key.length != 24 && key.length != 32) {
      throw ArgumentError('AES key length must be 16/24/32 bytes.');
    }
    if (iv.length != 16) {
      throw ArgumentError('AES CBC iv length must be 16 bytes.');
    }
    return _aesCbcPkcs7(false, encryptedBytes, key, iv);
  }
}
