using DigitalData.Core.Abstractions.Security.Key;
using DigitalData.Core.Abstractions.Security.Services;
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.RSAKey.Crypto;
using System.Security.Cryptography;

namespace DigitalData.Core.Security.Services;

public class RSAFactory : IAsymmetricKeyFactory
{
    public static readonly RSAFactory Static = new();

    public string CreatePrivateKeyPem(int? keySizeInBits = null, bool encrypt = false) => encrypt
        ? CreateEncryptedPrivateKeyPem(keySizeInBits: keySizeInBits)
        : RSA.Create(keySizeInBits ?? RSAParams.Default.KeySizeInBits).ExportRSAPrivateKeyPem();

    public string CreateEncryptedPrivateKeyPem(
        PbeEncryptionAlgorithm? pbeEncryptionAlgorithm = null,
        HashAlgorithmName? hashAlgorithmName = null,
        int? iterationCount = null,
        int? keySizeInBits = null,
        string? password = null)
    {
        password ??= RSAParams.Default.PbePassword;

        var pbeParameters = new PbeParameters(
                pbeEncryptionAlgorithm ?? RSAParams.Default.PbeEncryptionAlgorithm,
                hashAlgorithmName ?? RSAParams.Default.PbeHashAlgorithm,
                iterationCount ?? RSAParams.Default.PbeIterationCount);

        var encryptedPrivateKey = RSA.Create(keySizeInBits ?? RSAParams.Default.KeySizeInBits).ExportEncryptedPkcs8PrivateKey(password.AsSpan(), pbeParameters);

        var pemChars = PemEncoding.Write(RSAParams.Default.EncryptedPrivateKeyPemLabel, encryptedPrivateKey);

        return new string(pemChars);
    }

    public string CreateEncryptedPrivateKeyPem(
        PbeParameters pbeParameters,
        int? keySizeInBits = null,
        string? password = null)
    {
        password ??= RSAParams.Default.PbePassword;

        var encryptedPrivateKey = RSA.Create(keySizeInBits ?? RSAParams.Default.KeySizeInBits).ExportEncryptedPkcs8PrivateKey(password.AsSpan(), pbeParameters);

        var pemChars = PemEncoding.Write(RSAParams.Default.EncryptedPrivateKeyPemLabel, encryptedPrivateKey);

        return new string(pemChars);
    }

    public IAsymmetricDecryptor CreateDecryptor(string pem, string? issuer = null, string? audience = null, bool encrypt = false, RSAEncryptionPadding? padding = null) => new RSADecryptor()
    {
        Content = pem,
        IsEncrypted = encrypt,
        Padding = padding ?? RSAEncryptionPadding.OaepSHA256
    };
}