using System;
using System.Diagnostics.CodeAnalysis;

namespace StellaOps.Feedser.Source.Cve.Configuration;

public sealed class CveOptions
{
    public static string HttpClientName => "source.cve";

    public Uri BaseEndpoint { get; set; } = new("https://cveawg.mitre.org/api/", UriKind.Absolute);

    /// <summary>
    /// CVE Services requires an organisation identifier for authenticated requests.
    /// </summary>
    public string ApiOrg { get; set; } = string.Empty;

    /// <summary>
    /// CVE Services user identifier. Typically the username registered with the CVE Program.
    /// </summary>
    public string ApiUser { get; set; } = string.Empty;

    /// <summary>
    /// API key issued by the CVE Program for the configured organisation/user pair.
    /// </summary>
    public string ApiKey { get; set; } = string.Empty;

    /// <summary>
    /// Results fetched per page when querying CVE Services. Valid range 1-500.
    /// </summary>
    public int PageSize { get; set; } = 200;

    /// <summary>
    /// Maximum number of pages to fetch in a single run. Guards against runaway backfills.
    /// </summary>
    public int MaxPagesPerFetch { get; set; } = 5;

    /// <summary>
    /// Sliding look-back window when no previous cursor is available.
    /// </summary>
    public TimeSpan InitialBackfill { get; set; } = TimeSpan.FromDays(30);

    /// <summary>
    /// Delay between paginated requests to respect API throttling guidance.
    /// </summary>
    public TimeSpan RequestDelay { get; set; } = TimeSpan.FromMilliseconds(250);

    /// <summary>
    /// Backoff applied when the connector encounters an unrecoverable failure.
    /// </summary>
    public TimeSpan FailureBackoff { get; set; } = TimeSpan.FromMinutes(10);

    [MemberNotNull(nameof(BaseEndpoint), nameof(ApiOrg), nameof(ApiUser), nameof(ApiKey))]
    public void Validate()
    {
        if (BaseEndpoint is null || !BaseEndpoint.IsAbsoluteUri)
        {
            throw new InvalidOperationException("BaseEndpoint must be an absolute URI.");
        }

        if (string.IsNullOrWhiteSpace(ApiOrg))
        {
            throw new InvalidOperationException("ApiOrg must be provided.");
        }

        if (string.IsNullOrWhiteSpace(ApiUser))
        {
            throw new InvalidOperationException("ApiUser must be provided.");
        }

        if (string.IsNullOrWhiteSpace(ApiKey))
        {
            throw new InvalidOperationException("ApiKey must be provided.");
        }

        if (PageSize is < 1 or > 500)
        {
            throw new InvalidOperationException("PageSize must be between 1 and 500.");
        }

        if (MaxPagesPerFetch <= 0)
        {
            throw new InvalidOperationException("MaxPagesPerFetch must be a positive integer.");
        }

        if (InitialBackfill < TimeSpan.Zero)
        {
            throw new InvalidOperationException("InitialBackfill cannot be negative.");
        }

        if (RequestDelay < TimeSpan.Zero)
        {
            throw new InvalidOperationException("RequestDelay cannot be negative.");
        }

        if (FailureBackoff <= TimeSpan.Zero)
        {
            throw new InvalidOperationException("FailureBackoff must be greater than zero.");
        }
    }
}
