using System.Reflection;
using Microsoft.Extensions.Configuration;

namespace ZB.MOM.WW.ScadaBridge.Host.Tests;

public class OptionsTests
{
    /// <summary>
    /// Verify no component library (excluding Host) uses IConfiguration or accepts it
    /// in its AddXxx() extension method. Component libraries should only depend on
    /// DI abstractions and Options pattern, not on Configuration directly.
    /// </summary>
    [Fact]
    public void ComponentLibraries_DoNotAcceptIConfigurationInAddMethods()
    {
        // All component assemblies (excluding Host itself and Commons)
        var componentAssemblies = new[]
        {
            typeof(ClusterInfrastructure.ServiceCollectionExtensions).Assembly,
            typeof(Communication.ServiceCollectionExtensions).Assembly,
            typeof(HealthMonitoring.ServiceCollectionExtensions).Assembly,
            typeof(ExternalSystemGateway.ServiceCollectionExtensions).Assembly,
            typeof(NotificationService.ServiceCollectionExtensions).Assembly,
            typeof(NotificationOutbox.ServiceCollectionExtensions).Assembly,
            typeof(TemplateEngine.ServiceCollectionExtensions).Assembly,
            typeof(DeploymentManager.ServiceCollectionExtensions).Assembly,
            typeof(Security.ServiceCollectionExtensions).Assembly,
            typeof(ConfigurationDatabase.ServiceCollectionExtensions).Assembly,
            typeof(SiteRuntime.ServiceCollectionExtensions).Assembly,
            typeof(DataConnectionLayer.ServiceCollectionExtensions).Assembly,
            typeof(StoreAndForward.ServiceCollectionExtensions).Assembly,
            typeof(SiteEventLogging.ServiceCollectionExtensions).Assembly,
            typeof(CentralUI.ServiceCollectionExtensions).Assembly,
            typeof(InboundAPI.ServiceCollectionExtensions).Assembly,
        };

        foreach (var assembly in componentAssemblies)
        {
            // Check that the assembly does not reference Microsoft.Extensions.Configuration
            var configRef = assembly.GetReferencedAssemblies()
                .FirstOrDefault(a => a.Name == "Microsoft.Extensions.Configuration.Abstractions");

            // Find all public static extension methods named Add*
            var extensionClasses = assembly.GetExportedTypes()
                .Where(t => t.IsClass && t.IsAbstract && t.IsSealed); // static classes

            foreach (var cls in extensionClasses)
            {
                var addMethods = cls.GetMethods(BindingFlags.Public | BindingFlags.Static)
                    .Where(m => m.Name.StartsWith("Add") || m.Name.StartsWith("Map"));

                foreach (var method in addMethods)
                {
                    var parameters = method.GetParameters();
                    foreach (var param in parameters)
                    {
                        Assert.False(
                            typeof(IConfiguration).IsAssignableFrom(param.ParameterType),
                            $"{assembly.GetName().Name}: {cls.Name}.{method.Name} accepts IConfiguration parameter '{param.Name}'. " +
                            "Component libraries should use the Options pattern, not IConfiguration.");
                    }
                }
            }
        }
    }
}
