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

namespace FrontOffice.Main.Utilities;

public class MobileNumberEncryptor
{
    private readonly string _key;
    private readonly string _iv;
    public MobileNumberEncryptor(IConfiguration configuration)
    {
        var encryptionSettings = configuration
            .GetSection("EncryptionSettings")
            .Get<EncryptionSettings>()
            ?? throw new InvalidOperationException("EncryptionSettings section not found in configuration");

        _key = !string.IsNullOrWhiteSpace(encryptionSettings.Key)
            ? encryptionSettings.Key
            : throw new InvalidOperationException("Encryption Key not found in configuration");
        _iv = !string.IsNullOrWhiteSpace(encryptionSettings.IV)
            ? encryptionSettings.IV
            : throw new InvalidOperationException("Encryption IV not found in configuration");

        // اعتبارسنجی سایز
        ValidateKeyAndIv();
    }
    public MobileNumberEncryptor(string key, string iv)
    {
        _key = key;
        _iv = iv;
        ValidateKeyAndIv();
    }
    private void ValidateKeyAndIv()
    {
        try
        {
            byte[] keyBytes = Convert.FromBase64String(_key);
            byte[] ivBytes = Convert.FromBase64String(_iv);

            if (keyBytes.Length != 32)
                throw new ArgumentException("Key must be 32 bytes in Base64 format", nameof(_key));

            if (ivBytes.Length != 16)
                throw new ArgumentException("IV must be 16 bytes in Base64 format", nameof(_iv));
        }
        catch (FormatException)
        {
            throw new ArgumentException("Key or IV is not valid Base64 string");
        }
    }

    public string EncryptMobileNumber(string mobileNumber)
    {
        if (string.IsNullOrEmpty(mobileNumber))
            throw new ArgumentException("Mobile number cannot be null or empty", nameof(mobileNumber));

        try
        {
            byte[] key = Convert.FromBase64String(_key);
            byte[] iv = Convert.FromBase64String(_iv);
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(mobileNumber);

            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = key;
                aesAlg.IV = iv;
                aesAlg.Mode = CipherMode.CBC; // ECB ignores IV; CBC is standard with IV
                aesAlg.Padding = PaddingMode.PKCS7;

                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        csEncrypt.Write(plainTextBytes, 0, plainTextBytes.Length);
                        csEncrypt.FlushFinalBlock();

                        byte[] encryptedBytes = msEncrypt.ToArray();
                        return Convert.ToBase64String(encryptedBytes);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception($"Encryption failed: {ex.Message}", ex);
        }
    }

    public string DecryptMobileNumber(string encryptedMobileNumber)
    {
        if (string.IsNullOrEmpty(encryptedMobileNumber))
            throw new ArgumentException("Encrypted mobile number cannot be null or empty", nameof(encryptedMobileNumber));

        try
        {
            byte[] key = Convert.FromBase64String(_key);
            byte[] iv = Convert.FromBase64String(_iv);
            byte[] cipherTextBytes = Convert.FromBase64String(encryptedMobileNumber);

            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = key;
                aesAlg.IV = iv;
                aesAlg.Mode = CipherMode.CBC;
                aesAlg.Padding = PaddingMode.PKCS7;

                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                using (MemoryStream msDecrypt = new MemoryStream(cipherTextBytes))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            return srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception($"Decryption failed: {ex.Message}", ex);
        }
    }
}
