using ScadaLink.Commons.Types.Flattening;
using ScadaLink.TemplateEngine.Flattening;

namespace ScadaLink.TemplateEngine.Tests.Flattening;

public class RevisionHashServiceTests
{
    private readonly RevisionHashService _sut = new();

    [Fact]
    public void ComputeHash_SameContent_SameHash()
    {
        var config1 = CreateConfig("Instance1", "25.0");
        var config2 = CreateConfig("Instance1", "25.0");

        var hash1 = _sut.ComputeHash(config1);
        var hash2 = _sut.ComputeHash(config2);

        Assert.Equal(hash1, hash2);
    }

    [Fact]
    public void ComputeHash_DifferentContent_DifferentHash()
    {
        var config1 = CreateConfig("Instance1", "25.0");
        var config2 = CreateConfig("Instance1", "50.0");

        var hash1 = _sut.ComputeHash(config1);
        var hash2 = _sut.ComputeHash(config2);

        Assert.NotEqual(hash1, hash2);
    }

    [Fact]
    public void ComputeHash_StartsWithSha256Prefix()
    {
        var config = CreateConfig("Instance1", "25.0");
        var hash = _sut.ComputeHash(config);

        Assert.StartsWith("sha256:", hash);
    }

    [Fact]
    public void ComputeHash_DeterministicAcrossRuns()
    {
        // Different GeneratedAtUtc should NOT affect the hash (volatile field excluded)
        var config1 = new FlattenedConfiguration
        {
            InstanceUniqueName = "Instance1",
            TemplateId = 1,
            SiteId = 1,
            Attributes = [new ResolvedAttribute { CanonicalName = "A", Value = "1", DataType = "Int32" }],
            GeneratedAtUtc = new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero)
        };
        var config2 = new FlattenedConfiguration
        {
            InstanceUniqueName = "Instance1",
            TemplateId = 1,
            SiteId = 1,
            Attributes = [new ResolvedAttribute { CanonicalName = "A", Value = "1", DataType = "Int32" }],
            GeneratedAtUtc = new DateTimeOffset(2026, 6, 15, 12, 0, 0, TimeSpan.Zero)
        };

        Assert.Equal(_sut.ComputeHash(config1), _sut.ComputeHash(config2));
    }

    [Fact]
    public void ComputeHash_NullConfig_ThrowsArgumentNull()
    {
        Assert.Throws<ArgumentNullException>(() => _sut.ComputeHash(null!));
    }

    [Fact]
    public void ComputeHash_AttributeOrder_DoesNotAffectHash()
    {
        var config1 = new FlattenedConfiguration
        {
            InstanceUniqueName = "Instance1",
            TemplateId = 1,
            SiteId = 1,
            Attributes =
            [
                new ResolvedAttribute { CanonicalName = "A", Value = "1", DataType = "Int32" },
                new ResolvedAttribute { CanonicalName = "B", Value = "2", DataType = "Int32" }
            ]
        };
        var config2 = new FlattenedConfiguration
        {
            InstanceUniqueName = "Instance1",
            TemplateId = 1,
            SiteId = 1,
            Attributes =
            [
                new ResolvedAttribute { CanonicalName = "B", Value = "2", DataType = "Int32" },
                new ResolvedAttribute { CanonicalName = "A", Value = "1", DataType = "Int32" }
            ]
        };

        Assert.Equal(_sut.ComputeHash(config1), _sut.ComputeHash(config2));
    }

    private static FlattenedConfiguration CreateConfig(string instanceName, string tempValue)
    {
        return new FlattenedConfiguration
        {
            InstanceUniqueName = instanceName,
            TemplateId = 1,
            SiteId = 1,
            Attributes =
            [
                new ResolvedAttribute { CanonicalName = "Temperature", Value = tempValue, DataType = "Double" }
            ]
        };
    }
}
