using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using StellaOps.Feedser.Core.Jobs;
using StellaOps.Plugin.Hosting;

namespace StellaOps.Feedser.Core.Tests;

public sealed class JobPluginRegistrationExtensionsTests
{
    [Fact]
    public void RegisterJobPluginRoutines_LoadsPluginsAndRegistersDefinitions()
    {
        var services = new ServiceCollection();
        services.AddJobScheduler();

        var configuration = new ConfigurationBuilder()
            .AddInMemoryCollection(new Dictionary<string, string?>
            {
                ["plugin:test:timeoutSeconds"] = "45",
            })
            .Build();

        var assemblyPath = typeof(JobPluginRegistrationExtensionsTests).Assembly.Location;
        var pluginDirectory = Path.GetDirectoryName(assemblyPath)!;
        var pluginFile = Path.GetFileName(assemblyPath);

        var options = new PluginHostOptions
        {
            BaseDirectory = pluginDirectory,
            PluginsDirectory = pluginDirectory,
            EnsureDirectoryExists = false,
            RecursiveSearch = false,
        };
        options.SearchPatterns.Add(pluginFile);

        services.RegisterJobPluginRoutines(configuration, options);

        Assert.Contains(
            services,
            descriptor => descriptor.ServiceType == typeof(PluginHostResult));

        Assert.Contains(
            services,
            descriptor => descriptor.ServiceType.FullName == typeof(PluginRoutineExecuted).FullName);

        using var provider = services.BuildServiceProvider();
        var schedulerOptions = provider.GetRequiredService<IOptions<JobSchedulerOptions>>().Value;

        Assert.True(schedulerOptions.Definitions.TryGetValue(PluginJob.JobKind, out var definition));
        Assert.NotNull(definition);
        Assert.Equal(PluginJob.JobKind, definition.Kind);
        Assert.Equal("StellaOps.Feedser.Core.Tests.PluginJob", definition.JobType.FullName);
        Assert.Equal(TimeSpan.FromSeconds(45), definition.Timeout);
        Assert.Equal(TimeSpan.FromSeconds(5), definition.LeaseDuration);
        Assert.Equal("*/10 * * * *", definition.CronExpression);
    }
}
