using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using StellaOps.Authority.Plugins.Abstractions;
using StellaOps.Authority.Plugin.Standard.Storage;

namespace StellaOps.Authority.Plugin.Standard;

internal sealed class StandardIdentityProviderPlugin : IIdentityProviderPlugin
{
    private readonly ILogger<StandardIdentityProviderPlugin> logger;

    public StandardIdentityProviderPlugin(
        AuthorityPluginContext context,
        StandardUserCredentialStore credentialStore,
        StandardClientProvisioningStore clientProvisioningStore,
        IClaimsEnricher claimsEnricher,
        ILogger<StandardIdentityProviderPlugin> logger)
    {
        Context = context ?? throw new ArgumentNullException(nameof(context));
        Credentials = credentialStore ?? throw new ArgumentNullException(nameof(credentialStore));
        ClientProvisioning = clientProvisioningStore ?? throw new ArgumentNullException(nameof(clientProvisioningStore));
        ClaimsEnricher = claimsEnricher ?? throw new ArgumentNullException(nameof(claimsEnricher));
        this.logger = logger ?? throw new ArgumentNullException(nameof(logger));

        var manifestCapabilities = AuthorityIdentityProviderCapabilities.FromCapabilities(context.Manifest.Capabilities);
        if (!manifestCapabilities.SupportsPassword)
        {
            this.logger.LogWarning(
                "Standard Authority plugin '{PluginName}' manifest does not declare the 'password' capability. Forcing password support.",
                Context.Manifest.Name);
        }

        Capabilities = manifestCapabilities with { SupportsPassword = true };
    }

    public string Name => Context.Manifest.Name;

    public string Type => Context.Manifest.Type;

    public AuthorityPluginContext Context { get; }

    public IUserCredentialStore Credentials { get; }

    public IClaimsEnricher ClaimsEnricher { get; }

    public IClientProvisioningStore? ClientProvisioning { get; }

    public AuthorityIdentityProviderCapabilities Capabilities { get; }

    public async ValueTask<AuthorityPluginHealthResult> CheckHealthAsync(CancellationToken cancellationToken)
    {
        try
        {
            var store = (StandardUserCredentialStore)Credentials;
            return await store.CheckHealthAsync(cancellationToken).ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Standard Authority plugin '{PluginName}' health check failed.", Name);
            return AuthorityPluginHealthResult.Unavailable(ex.Message);
        }
    }
}
