using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Options;

namespace StellaOps.Scanner.Worker.Options;

public sealed class ScannerWorkerOptionsValidator : IValidateOptions<ScannerWorkerOptions>
{
    public ValidateOptionsResult Validate(string? name, ScannerWorkerOptions options)
    {
        ArgumentNullException.ThrowIfNull(options);

        var failures = new List<string>();

        if (options.MaxConcurrentJobs <= 0)
        {
            failures.Add("Scanner.Worker:MaxConcurrentJobs must be greater than zero.");
        }

        if (options.Queue.HeartbeatSafetyFactor < 2.0)
        {
            failures.Add("Scanner.Worker:Queue:HeartbeatSafetyFactor must be at least 2.");
        }

        if (options.Queue.MaxAttempts <= 0)
        {
            failures.Add("Scanner.Worker:Queue:MaxAttempts must be greater than zero.");
        }

        if (options.Queue.MinHeartbeatInterval <= TimeSpan.Zero)
        {
            failures.Add("Scanner.Worker:Queue:MinHeartbeatInterval must be greater than zero.");
        }

        if (options.Queue.MaxHeartbeatInterval <= options.Queue.MinHeartbeatInterval)
        {
            failures.Add("Scanner.Worker:Queue:MaxHeartbeatInterval must be greater than MinHeartbeatInterval.");
        }

        if (options.Polling.InitialDelay <= TimeSpan.Zero)
        {
            failures.Add("Scanner.Worker:Polling:InitialDelay must be greater than zero.");
        }

        if (options.Polling.MaxDelay < options.Polling.InitialDelay)
        {
            failures.Add("Scanner.Worker:Polling:MaxDelay must be greater than or equal to InitialDelay.");
        }

        if (options.Polling.JitterRatio is < 0 or > 1)
        {
            failures.Add("Scanner.Worker:Polling:JitterRatio must be between 0 and 1.");
        }

        if (options.Authority.Enabled)
        {
            if (string.IsNullOrWhiteSpace(options.Authority.Issuer))
            {
                failures.Add("Scanner.Worker:Authority requires Issuer when Enabled is true.");
            }

            if (string.IsNullOrWhiteSpace(options.Authority.ClientId))
            {
                failures.Add("Scanner.Worker:Authority requires ClientId when Enabled is true.");
            }

            if (options.Authority.BackchannelTimeoutSeconds <= 0)
            {
                failures.Add("Scanner.Worker:Authority:BackchannelTimeoutSeconds must be greater than zero.");
            }

            if (options.Authority.TokenClockSkewSeconds < 0)
            {
                failures.Add("Scanner.Worker:Authority:TokenClockSkewSeconds cannot be negative.");
            }

            if (options.Authority.Resilience.RetryDelays.Any(delay => delay <= TimeSpan.Zero))
            {
                failures.Add("Scanner.Worker:Authority:Resilience:RetryDelays must be positive durations.");
            }
        }

        if (options.Shutdown.Timeout < TimeSpan.FromSeconds(5))
        {
            failures.Add("Scanner.Worker:Shutdown:Timeout must be at least 5 seconds to allow lease completion.");
        }

        if (options.Telemetry.EnableTelemetry)
        {
            if (!options.Telemetry.EnableMetrics && !options.Telemetry.EnableTracing)
            {
                failures.Add("Scanner.Worker:Telemetry:EnableTelemetry requires metrics or tracing to be enabled.");
            }
        }

        return failures.Count == 0 ? ValidateOptionsResult.Success : ValidateOptionsResult.Fail(failures);
    }
}
