using System;
using System.IO;
using System.Text;
using StellaOps.Vexer.Policy;

namespace StellaOps.Vexer.Core.Tests;

public sealed class VexPolicyBinderTests
{
    private const string JsonPolicy = """
    {
      "version": "custom/v2",
      "weights": {
        "vendor": 0.95,
        "distro": 0.85
      },
      "providerOverrides": {
        "provider.example": 0.5
      }
    }
    """;

    private const string YamlPolicy = """
    version: custom/v3
    weights:
      vendor: 0.8
      distro: 0.7
      platform: 0.6
    providerOverrides:
      provider-a: 0.4
      provider-b: 0.3
    """;

    [Fact]
    public void Bind_Json_ReturnsNormalizedOptions()
    {
        var result = VexPolicyBinder.Bind(JsonPolicy, VexPolicyDocumentFormat.Json);

        Assert.True(result.Success);
        Assert.NotNull(result.Options);
        Assert.NotNull(result.NormalizedOptions);
        Assert.Equal("custom/v2", result.Options!.Version);
        Assert.Equal("custom/v2", result.NormalizedOptions!.Version);
        Assert.Empty(result.Issues);
    }

    [Fact]
    public void Bind_Yaml_ReturnsOverridesAndWarningsSorted()
    {
        var result = VexPolicyBinder.Bind(YamlPolicy, VexPolicyDocumentFormat.Yaml);

        Assert.True(result.Success);
        Assert.NotNull(result.NormalizedOptions);
        var overrides = result.NormalizedOptions!.ProviderOverrides;
        Assert.Equal(2, overrides.Count);
        Assert.Equal(0.4, overrides["provider-a"]);
        Assert.Equal(0.3, overrides["provider-b"]);
        Assert.Empty(result.Issues);
    }

    [Fact]
    public void Bind_InvalidJson_ReturnsError()
    {
        const string invalidJson = "{ \"weights\": { \"vendor\": \"not-a-number\" }";

        var result = VexPolicyBinder.Bind(invalidJson, VexPolicyDocumentFormat.Json);

        Assert.False(result.Success);
        var issue = Assert.Single(result.Issues);
        Assert.Equal(VexPolicyIssueSeverity.Error, issue.Severity);
        Assert.StartsWith("policy.parse.json", issue.Code, StringComparison.Ordinal);
    }

    [Fact]
    public void Bind_Stream_SupportsEncoding()
    {
        using var stream = new MemoryStream(Encoding.UTF8.GetBytes(JsonPolicy));
        var result = VexPolicyBinder.Bind(stream, VexPolicyDocumentFormat.Json);

        Assert.True(result.Success);
        Assert.NotNull(result.Options);
    }
}
