using System.Collections.Generic;

namespace StellaOps.Cryptography;

/// <summary>
/// High-level cryptographic capabilities supported by StellaOps providers.
/// </summary>
public enum CryptoCapability
{
    PasswordHashing,
    Signing,
    Verification,
    SymmetricEncryption,
    KeyDerivation
}

/// <summary>
/// Identifies a stored key or certificate handle.
/// </summary>
public sealed record CryptoKeyReference(string KeyId, string? ProviderHint = null);

/// <summary>
/// Contract implemented by crypto providers (BCL, CryptoPro, OpenSSL, etc.).
/// </summary>
public interface ICryptoProvider
{
    string Name { get; }

    bool Supports(CryptoCapability capability, string algorithmId);

    IPasswordHasher GetPasswordHasher(string algorithmId);

    /// <summary>
    /// Retrieves a signer for the supplied algorithm and key reference.
    /// </summary>
    /// <param name="algorithmId">Signing algorithm identifier (e.g., ES256).</param>
    /// <param name="keyReference">Key reference.</param>
    /// <returns>Signer instance.</returns>
    ICryptoSigner GetSigner(string algorithmId, CryptoKeyReference keyReference);

    /// <summary>
    /// Adds or replaces signing key material managed by this provider.
    /// </summary>
    /// <param name="signingKey">Key material descriptor.</param>
    void UpsertSigningKey(CryptoSigningKey signingKey);

    /// <summary>
    /// Removes signing key material by key identifier.
    /// </summary>
    /// <param name="keyId">Identifier to remove.</param>
    /// <returns><c>true</c> if the key was removed.</returns>
    bool RemoveSigningKey(string keyId);

    /// <summary>
    /// Lists signing key descriptors managed by this provider.
    /// </summary>
    IReadOnlyCollection<CryptoSigningKey> GetSigningKeys();
}

/// <summary>
/// Registry managing provider discovery and policy selection.
/// </summary>
public interface ICryptoProviderRegistry
{
    IReadOnlyCollection<ICryptoProvider> Providers { get; }

    bool TryResolve(string preferredProvider, out ICryptoProvider provider);

    ICryptoProvider ResolveOrThrow(CryptoCapability capability, string algorithmId);

    /// <summary>
    /// Resolves a signer for the supplied algorithm and key reference using registry policy.
    /// </summary>
    /// <param name="capability">Capability required (typically <see cref="CryptoCapability.Signing"/>).</param>
    /// <param name="algorithmId">Algorithm identifier.</param>
    /// <param name="keyReference">Key reference.</param>
    /// <param name="preferredProvider">Optional provider hint.</param>
    /// <returns>Resolved signer.</returns>
    CryptoSignerResolution ResolveSigner(
        CryptoCapability capability,
        string algorithmId,
        CryptoKeyReference keyReference,
        string? preferredProvider = null);
}

public sealed record CryptoSignerResolution(ICryptoSigner Signer, string ProviderName);
