using AgentSmith.Contracts.Commands;
using FluentAssertions;

namespace AgentSmith.Tests.Commands;

public class PipelinePresetsTests
{
    [Theory]
    [InlineData("fix-bug")]
    [InlineData("fix-no-test")]
    [InlineData("init-project")]
    [InlineData("add-feature")]
    public void TryResolve_KnownPreset_ReturnsCommands(string name)
    {
        var result = PipelinePresets.TryResolve(name);

        result.Should().NotBeNull();
        result!.Count.Should().BeGreaterThan(0);
    }

    [Fact]
    public void TryResolve_UnknownPreset_ReturnsNull()
    {
        PipelinePresets.TryResolve("nonexistent").Should().BeNull();
    }

    [Fact]
    public void TryResolve_CaseInsensitive()
    {
        PipelinePresets.TryResolve("Fix-Bug").Should().NotBeNull();
        PipelinePresets.TryResolve("INIT-PROJECT").Should().NotBeNull();
    }

    [Fact]
    public void FixBug_ContainsExpectedCommands()
    {
        PipelinePresets.FixBug.Should().Contain(CommandNames.FetchTicket);
        PipelinePresets.FixBug.Should().Contain(CommandNames.Test);
        PipelinePresets.FixBug.Should().Contain(CommandNames.CommitAndPR);
    }

    [Fact]
    public void ApiSecurityScan_FirstStepIsPipelineNameInitializer()
    {
        // p0125c: PipelineNameInitializer is prepended to every preset to publish
        // the pipeline_name concept once before any other handler runs.
        PipelinePresets.ApiSecurityScan[0].Should().Be(CommandNames.PipelineNameInitializer);
        PipelinePresets.ApiSecurityScan[1].Should().Be(CommandNames.TryCheckoutSource);
    }

    [Fact]
    public void FixNoTest_DoesNotContainTestCommand()
    {
        PipelinePresets.FixNoTest.Should().NotContain(CommandNames.Test);
        PipelinePresets.FixNoTest.Should().Contain(CommandNames.CommitAndPR);
    }

    [Fact]
    public void InitProject_ContainsKeyCommands()
    {
        // p0130c: BootstrapProject retired from this preset; replaced by the
        // AnalyzeCode → PublishProjectLanguage → LoadSkills → BootstrapDispatch
        // chain. Full step sequence is asserted in InitProjectPipelinePresetTests.
        PipelinePresets.InitProject.Should().Contain(CommandNames.PipelineNameInitializer);
        PipelinePresets.InitProject.Should().Contain(CommandNames.CheckoutSource);
        PipelinePresets.InitProject.Should().Contain(CommandNames.BootstrapDispatch);
        PipelinePresets.InitProject.Should().Contain(CommandNames.InitCommit);
        PipelinePresets.InitProject.Should().NotContain(CommandNames.BootstrapProject);
    }

    [Fact]
    public void AddFeature_ContainsGenerateTestsAndDocs()
    {
        PipelinePresets.AddFeature.Should().Contain(CommandNames.GenerateTests);
        PipelinePresets.AddFeature.Should().Contain(CommandNames.GenerateDocs);
    }

    [Theory]
    [InlineData("fix-bug")]
    [InlineData("fix-no-test")]
    [InlineData("add-feature")]
    public void MainPresets_ContainTriage(string name)
    {
        var preset = PipelinePresets.TryResolve(name);
        preset.Should().Contain(CommandNames.Triage);
    }

    [Fact]
    public void InitProject_DoesNotContainTriage()
    {
        PipelinePresets.InitProject.Should().NotContain(CommandNames.Triage);
    }

    [Fact]
    public void FixBug_RunVerifyPhase_AfterRunFinalPhaseBeforeCommitAndPR()
    {
        var list = PipelinePresets.FixBug.ToList();
        list.IndexOf(CommandNames.RunVerifyPhase).Should().BeGreaterThan(list.IndexOf(CommandNames.RunFinalPhase));
        list.IndexOf(CommandNames.RunVerifyPhase).Should().BeLessThan(list.IndexOf(CommandNames.CommitAndPR));
    }

    [Fact]
    public void AddFeature_RunVerifyPhase_AfterRunFinalPhaseBeforeCommitAndPR()
    {
        var list = PipelinePresets.AddFeature.ToList();
        list.IndexOf(CommandNames.RunVerifyPhase).Should().BeGreaterThan(list.IndexOf(CommandNames.RunFinalPhase));
        list.IndexOf(CommandNames.RunVerifyPhase).Should().BeLessThan(list.IndexOf(CommandNames.CommitAndPR));
    }

    [Fact]
    public void FixNoTest_DoesNotContainRunVerifyPhase()
    {
        PipelinePresets.FixNoTest.Should().NotContain(CommandNames.RunVerifyPhase);
    }

    [Fact]
    public void NonImplementationPresets_DoNotContainRunVerifyPhase()
    {
        PipelinePresets.SecurityScan.Should().NotContain(CommandNames.RunVerifyPhase);
        PipelinePresets.ApiSecurityScan.Should().NotContain(CommandNames.RunVerifyPhase);
        PipelinePresets.MadDiscussion.Should().NotContain(CommandNames.RunVerifyPhase);
        PipelinePresets.InitProject.Should().NotContain(CommandNames.RunVerifyPhase);
    }

    [Theory]
    [InlineData("fix-bug")]
    [InlineData("fix-no-test")]
    [InlineData("add-feature")]
    public void MainPresets_TriageBeforeGeneratePlan(string name)
    {
        var preset = PipelinePresets.TryResolve(name)!;
        var triageIndex = preset.ToList().IndexOf(CommandNames.Triage);
        var planIndex = preset.ToList().IndexOf(CommandNames.GeneratePlan);
        triageIndex.Should().BeLessThan(planIndex, "Triage must run before GeneratePlan");
    }
}
