using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace StellaOps.Policy.Tests;

public sealed class PolicyBinderTests
{
    [Fact]
    public void Bind_ValidYaml_ReturnsSuccess()
    {
        const string yaml = """
        version: "1.0"
        rules:
          - name: Block Critical
            severity: [Critical]
            sources: [NVD]
            action: block
        """;

        var result = PolicyBinder.Bind(yaml, PolicyDocumentFormat.Yaml);

        Assert.True(result.Success);
        Assert.Equal("1.0", result.Document.Version);
        Assert.Single(result.Document.Rules);
        Assert.Empty(result.Issues);
    }

    [Fact]
    public void Bind_InvalidSeverity_ReturnsError()
    {
        const string yaml = """
        version: "1.0"
        rules:
          - name: Invalid Severity
            severity: [Nope]
            action: block
        """;

        var result = PolicyBinder.Bind(yaml, PolicyDocumentFormat.Yaml);

        Assert.False(result.Success);
        Assert.Contains(result.Issues, issue => issue.Code == "policy.severity.invalid");
    }

    [Fact]
    public async Task Cli_StrictMode_FailsOnWarnings()
    {
        const string yaml = """
        version: "1.0"
        rules:
          - name: Quiet Warning
            sources: ["", "NVD"]
            action: ignore
        """;

        var path = Path.Combine(Path.GetTempPath(), $"policy-{Guid.NewGuid():N}.yaml");
        await File.WriteAllTextAsync(path, yaml);

        try
        {
            using var output = new StringWriter();
            using var error = new StringWriter();
            var cli = new PolicyValidationCli(output, error);
            var options = new PolicyValidationCliOptions
            {
                Inputs = new[] { path },
                Strict = true,
            };

            var exitCode = await cli.RunAsync(options, CancellationToken.None);

            Assert.Equal(2, exitCode);
            Assert.Contains("WARNING", output.ToString());
        }
        finally
        {
            if (File.Exists(path))
            {
                File.Delete(path);
            }
        }
    }
}
