using System.Collections.Generic;
using System.IO.Abstractions;

namespace StellaOps.Excititor.Connectors.RedHat.CSAF.Configuration;

public sealed class RedHatConnectorOptions
{
    public static readonly Uri DefaultMetadataUri = new("https://access.redhat.com/.well-known/csaf/provider-metadata.json");

    /// <summary>
    /// HTTP client name registered for the connector.
    /// </summary>
    public const string HttpClientName = "excititor.connector.redhat";

    /// <summary>
    /// URI of the CSAF provider metadata document.
    /// </summary>
    public Uri MetadataUri { get; set; } = DefaultMetadataUri;

    /// <summary>
    /// Duration to cache loaded metadata before refreshing.
    /// </summary>
    public TimeSpan MetadataCacheDuration { get; set; } = TimeSpan.FromHours(1);

    /// <summary>
    /// Optional file path used to store or source offline metadata snapshots.
    /// </summary>
    public string? OfflineSnapshotPath { get; set; }

    /// <summary>
    /// When true, the loader prefers the offline snapshot without attempting a network fetch.
    /// </summary>
    public bool PreferOfflineSnapshot { get; set; }

    /// <summary>
    /// Enables writing fresh metadata responses to <see cref="OfflineSnapshotPath"/>.
    /// </summary>
    public bool PersistOfflineSnapshot { get; set; } = true;

    /// <summary>
    /// Explicit trust weight override applied to the provider entry.
    /// </summary>
    public double TrustWeight { get; set; } = 1.0;

    /// <summary>
    /// Sigstore/Cosign issuer used to verify CSAF signatures, if published.
    /// </summary>
    public string? CosignIssuer { get; set; } = "https://access.redhat.com";

    /// <summary>
    /// Identity pattern matched against the Cosign certificate subject.
    /// </summary>
    public string? CosignIdentityPattern { get; set; } = "^https://access\\.redhat\\.com/.+$";

    /// <summary>
    /// Optional list of PGP fingerprints recognised for Red Hat CSAF artifacts.
    /// </summary>
    public IList<string> PgpFingerprints { get; } = new List<string>();

    public void Validate(IFileSystem? fileSystem = null)
    {
        if (MetadataUri is null || !MetadataUri.IsAbsoluteUri)
        {
            throw new InvalidOperationException("Metadata URI must be absolute.");
        }

        if (MetadataUri.Scheme is not ("http" or "https"))
        {
            throw new InvalidOperationException("Metadata URI must use HTTP or HTTPS.");
        }

        if (MetadataCacheDuration <= TimeSpan.Zero)
        {
            throw new InvalidOperationException("Metadata cache duration must be positive.");
        }

        if (!string.IsNullOrWhiteSpace(OfflineSnapshotPath))
        {
            var fs = fileSystem ?? new FileSystem();
            var directory = Path.GetDirectoryName(OfflineSnapshotPath);
            if (!string.IsNullOrWhiteSpace(directory) && !fs.Directory.Exists(directory))
            {
                fs.Directory.CreateDirectory(directory);
            }
        }

        if (double.IsNaN(TrustWeight) || double.IsInfinity(TrustWeight) || TrustWeight <= 0)
        {
            TrustWeight = 1.0;
        }
        else if (TrustWeight > 1.0)
        {
            TrustWeight = 1.0;
        }

        if (CosignIssuer is not null)
        {
            if (string.IsNullOrWhiteSpace(CosignIdentityPattern))
            {
                throw new InvalidOperationException("CosignIdentityPattern must be provided when CosignIssuer is specified.");
            }
        }
    }
}
