using AgentSmith.Contracts.Models.Configuration;
using AgentSmith.Domain.Exceptions;
using AgentSmith.Infrastructure.Core.Services.Configuration;
using FluentAssertions;

namespace AgentSmith.Tests.Configuration;

public class ProjectConfigNormalizerTests
{
    private readonly ProjectConfigNormalizer _sut = new();

    [Fact]
    public void Normalize_LegacyPipelineString_TranslatesToPipelinesAndDefaultPipeline()
    {
        var project = new RawProjectEntry { Pipeline = "fix-bug" };

        _sut.Normalize("p", project);

        project.Pipelines.Should().HaveCount(1);
        project.Pipelines[0].Name.Should().Be("fix-bug");
        project.DefaultPipeline.Should().Be("fix-bug");
    }

    [Fact]
    public void Normalize_LegacySkillsPathDefaultValue_NotCarriedToPipelineDefinition()
    {
        var project = new RawProjectEntry { Pipeline = "fix-bug", SkillsPath = "skills/coding" };

        _sut.Normalize("p", project);

        project.Pipelines[0].SkillsPath.Should().BeNull();
    }

    [Fact]
    public void Normalize_LegacySkillsPathCustomValue_CarriedToPipelineDefinition()
    {
        var project = new RawProjectEntry { Pipeline = "security-scan", SkillsPath = "skills/security" };

        _sut.Normalize("p", project);

        project.Pipelines[0].SkillsPath.Should().Be("skills/security");
    }

    [Fact]
    public void Normalize_BothLegacyAndPipelinesSet_LegacyAddedAsAdditionalPipeline()
    {
        var project = new RawProjectEntry
        {
            Pipeline = "fix-bug",
            Pipelines = [new RawPipelineEntry { Name = "security-scan" }],
        };

        _sut.Normalize("p", project);

        project.Pipelines.Should().HaveCount(2);
        project.Pipelines.Should().Contain(p => p.Name == "fix-bug");
        project.Pipelines.Should().Contain(p => p.Name == "security-scan");
        project.DefaultPipeline.Should().Be("fix-bug");
    }

    [Fact]
    public void Normalize_LegacyPipelineAlreadyInPipelinesList_NotDuplicated()
    {
        var project = new RawProjectEntry
        {
            Pipeline = "fix-bug",
            Pipelines = [new RawPipelineEntry { Name = "fix-bug", SkillsPath = "skills/custom" }],
        };

        _sut.Normalize("p", project);

        project.Pipelines.Should().HaveCount(1);
        project.Pipelines[0].SkillsPath.Should().Be("skills/custom");
    }

    [Fact]
    public void Normalize_DefaultPipelineNotInPipelinesList_ThrowsConfigurationException()
    {
        var project = new RawProjectEntry
        {
            DefaultPipeline = "missing",
            Pipelines = [new RawPipelineEntry { Name = "fix-bug" }],
        };

        Action act = () => _sut.Normalize("proj", project);

        act.Should().Throw<ConfigurationException>()
            .WithMessage("*default_pipeline*missing*");
    }

    [Fact]
    public void Normalize_TriggerPipelineFromLabelReferencesUndeclaredPipeline_DoesNotThrow()
    {
        var project = new RawProjectEntry
        {
            Pipelines = [new RawPipelineEntry { Name = "fix-bug" }],
            GithubTrigger = new WebhookTriggerConfig
            {
                PipelineFromLabel = new Dictionary<string, string> { ["security-review"] = "security-scan" }
            }
        };

        Action act = () => _sut.Normalize("proj", project);

        act.Should().NotThrow();
    }

    [Fact]
    public void Normalize_PipelinesAlreadySetAndNoLegacy_NoChange()
    {
        var project = new RawProjectEntry
        {
            Pipelines =
            [
                new RawPipelineEntry { Name = "a" },
                new RawPipelineEntry { Name = "b" },
            ],
        };

        _sut.Normalize("p", project);

        project.Pipelines.Should().HaveCount(2);
        project.DefaultPipeline.Should().BeNull();
    }
}
