using System.Collections.Immutable;

namespace StellaOps.Vexer.Core;

public sealed record VexConsensusPolicyOptions
{
    public const string BaselineVersion = "baseline/v1";

    public VexConsensusPolicyOptions(
        string? version = null,
        double vendorWeight = 1.0,
        double distroWeight = 0.9,
        double platformWeight = 0.7,
        double hubWeight = 0.5,
        double attestationWeight = 0.6,
        IEnumerable<KeyValuePair<string, double>>? providerOverrides = null)
    {
        Version = string.IsNullOrWhiteSpace(version) ? BaselineVersion : version.Trim();
        VendorWeight = NormalizeWeight(vendorWeight);
        DistroWeight = NormalizeWeight(distroWeight);
        PlatformWeight = NormalizeWeight(platformWeight);
        HubWeight = NormalizeWeight(hubWeight);
        AttestationWeight = NormalizeWeight(attestationWeight);
        ProviderOverrides = NormalizeOverrides(providerOverrides);
    }

    public string Version { get; }

    public double VendorWeight { get; }

    public double DistroWeight { get; }

    public double PlatformWeight { get; }

    public double HubWeight { get; }

    public double AttestationWeight { get; }

    public ImmutableDictionary<string, double> ProviderOverrides { get; }

    private static double NormalizeWeight(double weight)
    {
        if (double.IsNaN(weight) || double.IsInfinity(weight))
        {
            throw new ArgumentOutOfRangeException(nameof(weight), "Weight must be a finite number.");
        }

        if (weight <= 0)
        {
            return 0;
        }

        if (weight >= 1)
        {
            return 1;
        }

        return weight;
    }

    private static ImmutableDictionary<string, double> NormalizeOverrides(
        IEnumerable<KeyValuePair<string, double>>? overrides)
    {
        if (overrides is null)
        {
            return ImmutableDictionary<string, double>.Empty;
        }

        var builder = ImmutableDictionary.CreateBuilder<string, double>(StringComparer.Ordinal);
        foreach (var (key, weight) in overrides)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                continue;
            }

            builder[key.Trim()] = NormalizeWeight(weight);
        }

        return builder.ToImmutable();
    }
}
