using System.Net;

namespace StellaOps.Feedser.Source.CertBund.Configuration;

public sealed class CertBundOptions
{
    public const string HttpClientName = "feedser.source.certbund";

    /// <summary>
    /// RSS feed providing the latest CERT-Bund advisories.
    /// </summary>
    public Uri FeedUri { get; set; } = new("https://wid.cert-bund.de/content/public/securityAdvisory/rss");

    /// <summary>
    /// Portal endpoint used to bootstrap session cookies (required for the SPA JSON API).
    /// </summary>
    public Uri PortalBootstrapUri { get; set; } = new("https://wid.cert-bund.de/portal/");

    /// <summary>
    /// Detail API endpoint template; advisory identifier is appended as the <c>name</c> query parameter.
    /// </summary>
    public Uri DetailApiUri { get; set; } = new("https://wid.cert-bund.de/portal/api/securityadvisory");

    /// <summary>
    /// Optional timeout override for feed/detail requests.
    /// </summary>
    public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(30);

    /// <summary>
    /// Delay applied between successive detail fetches to respect upstream politeness.
    /// </summary>
    public TimeSpan RequestDelay { get; set; } = TimeSpan.FromMilliseconds(250);

    /// <summary>
    /// Backoff recorded in source state when a fetch attempt fails.
    /// </summary>
    public TimeSpan FailureBackoff { get; set; } = TimeSpan.FromMinutes(5);

    /// <summary>
    /// Maximum number of advisories to enqueue per fetch iteration.
    /// </summary>
    public int MaxAdvisoriesPerFetch { get; set; } = 50;

    /// <summary>
    /// Maximum number of advisory identifiers remembered to prevent re-processing.
    /// </summary>
    public int MaxKnownAdvisories { get; set; } = 512;

    public void Validate()
    {
        if (FeedUri is null || !FeedUri.IsAbsoluteUri)
        {
            throw new InvalidOperationException("CERT-Bund feed URI must be an absolute URI.");
        }

        if (PortalBootstrapUri is null || !PortalBootstrapUri.IsAbsoluteUri)
        {
            throw new InvalidOperationException("CERT-Bund portal bootstrap URI must be an absolute URI.");
        }

        if (DetailApiUri is null || !DetailApiUri.IsAbsoluteUri)
        {
            throw new InvalidOperationException("CERT-Bund detail API URI must be an absolute URI.");
        }

        if (RequestTimeout <= TimeSpan.Zero)
        {
            throw new InvalidOperationException($"{nameof(RequestTimeout)} must be positive.");
        }

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

        if (FailureBackoff <= TimeSpan.Zero)
        {
            throw new InvalidOperationException($"{nameof(FailureBackoff)} must be positive.");
        }

        if (MaxAdvisoriesPerFetch <= 0)
        {
            throw new InvalidOperationException($"{nameof(MaxAdvisoriesPerFetch)} must be greater than zero.");
        }

        if (MaxKnownAdvisories <= 0)
        {
            throw new InvalidOperationException($"{nameof(MaxKnownAdvisories)} must be greater than zero.");
        }
    }

    public Uri BuildDetailUri(string advisoryId)
    {
        if (string.IsNullOrWhiteSpace(advisoryId))
        {
            throw new ArgumentException("Advisory identifier must be provided.", nameof(advisoryId));
        }

        var builder = new UriBuilder(DetailApiUri);
        var queryPrefix = string.IsNullOrEmpty(builder.Query) ? string.Empty : builder.Query.TrimStart('?') + "&";
        builder.Query = $"{queryPrefix}name={Uri.EscapeDataString(advisoryId)}";
        return builder.Uri;
    }
}
