using System;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Authority.Plugins;
using StellaOps.Authority.Plugins.Abstractions;

namespace StellaOps.Authority.Tests.Plugins;

public class AuthorityPluginLoaderTests
{
    [Fact]
    public void RegisterPlugins_ReturnsEmptySummary_WhenNoPluginsConfigured()
    {
        var services = new ServiceCollection();
        var configuration = new ConfigurationBuilder().Build();

        var summary = AuthorityPluginLoader.RegisterPluginsCore(
            services,
            configuration,
            Array.Empty<AuthorityPluginContext>(),
            Array.Empty<AuthorityPluginLoader.LoadedPluginDescriptor>(),
            Array.Empty<string>(),
            NullLogger.Instance);

        Assert.Empty(summary.RegisteredPlugins);
        Assert.Empty(summary.Failures);
        Assert.Empty(summary.MissingOrderedPlugins);
    }

    [Fact]
    public void RegisterPlugins_RecordsFailure_WhenAssemblyMissing()
    {
        var services = new ServiceCollection();
        var hostConfiguration = new ConfigurationBuilder().Build();

        var manifest = new AuthorityPluginManifest(
            "standard",
            "standard",
            true,
            "StellaOps.Authority.Plugin.Standard",
            null,
            Array.Empty<string>(),
            new Dictionary<string, string?>(),
            "standard.yaml");

        var contexts = new[]
        {
            new AuthorityPluginContext(manifest, hostConfiguration)
        };

        var summary = AuthorityPluginLoader.RegisterPluginsCore(
            services,
            hostConfiguration,
            contexts,
            Array.Empty<AuthorityPluginLoader.LoadedPluginDescriptor>(),
            Array.Empty<string>(),
            NullLogger.Instance);

        var failure = Assert.Single(summary.Failures);
        Assert.Equal("standard", failure.PluginName);
        Assert.Contains("Assembly", failure.Reason, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public void RegisterPlugins_RegistersEnabledPlugin_WhenRegistrarAvailable()
    {
        var services = new ServiceCollection();
        var hostConfiguration = new ConfigurationBuilder().Build();

        var manifest = new AuthorityPluginManifest(
            "test",
            TestAuthorityPluginRegistrar.PluginTypeIdentifier,
            true,
            typeof(TestAuthorityPluginRegistrar).Assembly.GetName().Name,
            typeof(TestAuthorityPluginRegistrar).Assembly.Location,
            Array.Empty<string>(),
            new Dictionary<string, string?>(),
            "test.yaml");

        var pluginContext = new AuthorityPluginContext(manifest, hostConfiguration);
        var descriptor = new AuthorityPluginLoader.LoadedPluginDescriptor(
            typeof(TestAuthorityPluginRegistrar).Assembly,
            typeof(TestAuthorityPluginRegistrar).Assembly.Location);

        var summary = AuthorityPluginLoader.RegisterPluginsCore(
            services,
            hostConfiguration,
            new[] { pluginContext },
            new[] { descriptor },
            Array.Empty<string>(),
            NullLogger.Instance);

        Assert.Contains("test", summary.RegisteredPlugins);
        Assert.Empty(summary.Failures);

        var provider = services.BuildServiceProvider();
        Assert.NotNull(provider.GetRequiredService<TestMarkerService>());
    }

    private sealed class TestAuthorityPluginRegistrar : IAuthorityPluginRegistrar
    {
        public const string PluginTypeIdentifier = "test-plugin";

        public string PluginType => PluginTypeIdentifier;

        public void Register(AuthorityPluginRegistrationContext context)
        {
            context.Services.AddSingleton<TestMarkerService>();
        }
    }

    private sealed class TestMarkerService
    {
    }
}
