using System.Security.Cryptography;
using System.Text;

namespace NPin.Framework.Core.Crypt.AES;

public static class AesCrypt
{
    /// <summary>
    /// 盐
    /// </summary>
    private const string Slat = "Q+OFqu]luparUP;Xn^_ktHX^FoWiK4C#;daRV(b1bbT_;HrrAL";
    
    /// <summary>
    /// 处理key
    /// </summary>
    /// <param name="pwd">输入的密码</param>
    /// <param name="model">Key和IV模式</param>
    /// <returns></returns>
    private static Tuple<byte[], byte[]> GetAesKey(string pwd, AesKeyEnum model = AesKeyEnum.AES256)
    {
        var hash1 = $"{pwd}-{Slat}".Md5();
        switch (model)
        {
            case AesKeyEnum.AES256:
            {
                var hash2 = $"{hash1}-{Slat}".Md5();
                var hash3 = $"{hash2}-{Slat}".To16Md5();
                var key = Encoding.UTF8.GetBytes($"{hash1}{hash2}".Md5());
                var iv = Encoding.UTF8.GetBytes(hash3);
                return new(key, iv);
            }
            case AesKeyEnum.AES128:
            {
                var hash2 = $"{hash1}-{Slat}".To16Md5();
                var key = Encoding.UTF8.GetBytes(hash1);
                var iv = Encoding.UTF8.GetBytes(hash2);
                return new(key, iv);
            }
            default: throw new("不支持的类型");
        }
    }

    /// <summary>
    /// AES加密
    /// </summary>
    /// <param name="content">待加密数据</param>
    /// <param name="pwd">密钥</param>
    /// <param name="model">Aes密钥模式</param>
    /// <param name="mode">加密模式</param>
    /// <param name="padding">填充模式</param>
    /// <returns></returns>
    public static byte[] Encrypt(byte[] content, string pwd, AesKeyEnum model, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
    {
        var (Key, IV) = GetAesKey(pwd, model);
        using var aes = Aes.Create();
        aes.Key = Key;
        aes.IV = IV;
        aes.Mode = mode;
        aes.Padding = padding;
        var cTransform = aes.CreateEncryptor();
        return cTransform.TransformFinalBlock(content, 0, content.Length);
    }

    /// <summary>
    /// AES解密
    /// </summary>
    /// <param name="secret">待解密数据</param>
    /// <param name="pwd">密钥</param>
    /// <param name="model">Aes密钥模式</param>
    /// <param name="mode">加密模式</param>
    /// <param name="padding">填充模式</param>
    /// <returns></returns>
    public static byte[] Decrypt(byte[] secret, string pwd, AesKeyEnum model, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
    {
        var (key, iv) = GetAesKey(pwd, model);
        using var aes = Aes.Create();
        aes.Key = key;
        aes.IV = iv;
        aes.Mode = mode;
        aes.Padding = padding;
        var cTransform = aes.CreateDecryptor();
        return cTransform.TransformFinalBlock(secret, 0, secret.Length);
    }
}