using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using StellaOps.Feedser.Core.Jobs;

namespace StellaOps.Feedser.Core.Tests;

public sealed class JobSchedulerBuilderTests
{
    [Fact]
    public void AddJob_RegistersDefinitionWithExplicitMetadata()
    {
        var services = new ServiceCollection();
        var builder = services.AddJobScheduler();

        builder.AddJob<TestJob>(
            kind: "jobs:test",
            cronExpression: "*/5 * * * *",
            timeout: TimeSpan.FromMinutes(42),
            leaseDuration: TimeSpan.FromMinutes(7),
            enabled: false);

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

        Assert.True(options.Definitions.TryGetValue("jobs:test", out var definition));
        Assert.NotNull(definition);
        Assert.Equal(typeof(TestJob), definition.JobType);
        Assert.Equal(TimeSpan.FromMinutes(42), definition.Timeout);
        Assert.Equal(TimeSpan.FromMinutes(7), definition.LeaseDuration);
        Assert.Equal("*/5 * * * *", definition.CronExpression);
        Assert.False(definition.Enabled);
    }

    [Fact]
    public void AddJob_UsesDefaults_WhenOptionalMetadataExcluded()
    {
        var services = new ServiceCollection();
        var builder = services.AddJobScheduler(options =>
        {
            options.DefaultTimeout = TimeSpan.FromSeconds(123);
            options.DefaultLeaseDuration = TimeSpan.FromSeconds(45);
        });

        builder.AddJob<DefaultedJob>(kind: "jobs:defaults");

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

        Assert.True(options.Definitions.TryGetValue("jobs:defaults", out var definition));
        Assert.NotNull(definition);
        Assert.Equal(typeof(DefaultedJob), definition.JobType);
        Assert.Equal(TimeSpan.FromSeconds(123), definition.Timeout);
        Assert.Equal(TimeSpan.FromSeconds(45), definition.LeaseDuration);
        Assert.Null(definition.CronExpression);
        Assert.True(definition.Enabled);
    }

    private sealed class TestJob : IJob
    {
        public Task ExecuteAsync(JobExecutionContext context, CancellationToken cancellationToken)
            => Task.CompletedTask;
    }

    private sealed class DefaultedJob : IJob
    {
        public Task ExecuteAsync(JobExecutionContext context, CancellationToken cancellationToken)
            => Task.CompletedTask;
    }
}
