using JobTrackerApi.Services;
using Microsoft.Extensions.Configuration;
using Xunit;

namespace JobTrackerApi.Tests;

// Pins the configuration KEY, not just the behaviour. /health previously read the
// APP_VERSION environment variable while docker-compose passed App__Version, so the
// endpoint silently reported "unknown" in every container. Nothing failed; the value
// was just wrong. These tests fail if the key drifts again.
public sealed class BuildMetadataTests
{
    private static IConfiguration Config(params (string Key, string Value)[] values) =>
        new ConfigurationBuilder()
            .AddInMemoryCollection(values.Select(v => new KeyValuePair<string, string?>(v.Key, v.Value)))
            .Build();

    [Fact]
    public void Reads_the_App_Version_configuration_key()
    {
        var version = BuildMetadata.ResolveVersion(Config(("App:Version", "1.2.3")));

        Assert.Equal("1.2.3", version);
    }

    [Fact]
    public void App__Version_environment_variable_binds_to_the_same_key()
    {
        // This is the exact path docker-compose uses: App__Version in the container
        // environment must reach App:Version in configuration.
        var cfg = new ConfigurationBuilder()
            .AddInMemoryCollection(new Dictionary<string, string?>())
            .Add(new FakeEnvironmentSource(("App__Version", "42")))
            .Build();

        Assert.Equal("42", BuildMetadata.ResolveVersion(cfg));
    }

    [Fact]
    public void Falls_back_to_the_assembly_version_when_unconfigured()
    {
        // Local development sets nothing. "unknown" would be a regression, not a default.
        var version = BuildMetadata.ResolveVersion(Config());

        Assert.False(string.IsNullOrWhiteSpace(version));
        Assert.NotEqual("unknown", version);
    }

    [Theory]
    [InlineData("$(git rev-parse --short HEAD)")]
    [InlineData("${APP_COMMIT_SHA}")]
    [InlineData("   ")]
    [InlineData(null)]
    public void Unresolved_placeholders_and_blanks_are_rejected(string? raw)
    {
        Assert.Null(BuildMetadata.Normalize(raw));
    }

    [Fact]
    public void A_real_value_survives_normalization_trimmed()
    {
        Assert.Equal("abc1234", BuildMetadata.Normalize("  abc1234  "));
    }

    // Minimal stand-in for the environment-variable provider, so the test does not
    // mutate the real process environment and race other tests.
    private sealed class FakeEnvironmentSource : IConfigurationSource
    {
        private readonly (string Key, string Value)[] _values;

        public FakeEnvironmentSource(params (string Key, string Value)[] values) => _values = values;

        public IConfigurationProvider Build(IConfigurationBuilder builder) => new Provider(_values);

        private sealed class Provider : ConfigurationProvider
        {
            private readonly (string Key, string Value)[] _values;

            public Provider((string Key, string Value)[] values) => _values = values;

            public override void Load()
            {
                foreach (var (key, value) in _values)
                {
                    // "__" is the environment-variable spelling of the ":" section separator.
                    Data[key.Replace("__", ":")] = value;
                }
            }
        }
    }
}
