using System.Collections.ObjectModel;

namespace StellaOps.Feedser.Source.Common.Http;

/// <summary>
/// Configuration applied to named HTTP clients used by connectors.
/// </summary>
public sealed class SourceHttpClientOptions
{
    private readonly HashSet<string> _allowedHosts = new(StringComparer.OrdinalIgnoreCase);
    private readonly Dictionary<string, string> _defaultHeaders = new(StringComparer.OrdinalIgnoreCase);

    /// <summary>
    /// Gets or sets the base address used for relative requests.
    /// </summary>
    public Uri? BaseAddress { get; set; }

    /// <summary>
    /// Gets or sets the client timeout.
    /// </summary>
    public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30);

    /// <summary>
    /// Gets or sets the user-agent string applied to outgoing requests.
    /// </summary>
    public string UserAgent { get; set; } = "StellaOps.Feedser/1.0";

    /// <summary>
    /// Gets or sets whether redirects are allowed. Defaults to <c>true</c>.
    /// </summary>
    public bool AllowAutoRedirect { get; set; } = true;

    /// <summary>
    /// Maximum number of retry attempts for transient failures.
    /// </summary>
    public int MaxAttempts { get; set; } = 3;

    /// <summary>
    /// Base delay applied to the exponential backoff policy.
    /// </summary>
    public TimeSpan BaseDelay { get; set; } = TimeSpan.FromSeconds(2);

    /// <summary>
    /// Hosts that this client is allowed to contact.
    /// </summary>
    public ISet<string> AllowedHosts => _allowedHosts;

    /// <summary>
    /// Default request headers appended to each outgoing request.
    /// </summary>
    public IDictionary<string, string> DefaultRequestHeaders => _defaultHeaders;

    internal SourceHttpClientOptions Clone()
    {
        var clone = new SourceHttpClientOptions
        {
            BaseAddress = BaseAddress,
            Timeout = Timeout,
            UserAgent = UserAgent,
            AllowAutoRedirect = AllowAutoRedirect,
            MaxAttempts = MaxAttempts,
            BaseDelay = BaseDelay,
        };

        foreach (var host in _allowedHosts)
        {
            clone.AllowedHosts.Add(host);
        }

        foreach (var header in _defaultHeaders)
        {
            clone.DefaultRequestHeaders[header.Key] = header.Value;
        }

        return clone;
    }

    internal IReadOnlyCollection<string> GetAllowedHostsSnapshot()
        => new ReadOnlyCollection<string>(_allowedHosts.ToArray());
}
