using SolutionErp.Application.PurchaseEvaluations;
using SolutionErp.Domain.Contracts;   // WorkflowApproverKind reuse
using SolutionErp.Domain.Identity;
using SolutionErp.Domain.PurchaseEvaluations;
using SolutionErp.Infrastructure.Tests.Common;

namespace SolutionErp.Infrastructure.Tests.Application;

// Tests cho PeWorkflowAdminFeatures (PE Workflow Designer admin UI — session 5).
// Mục tiêu: chống regression Versioning logic (auto-increment + deactivate cũ),
// vì invariant "AT MOST ONE IsActive=true per EvaluationType" rất quan trọng.
public class CreatePeWorkflowDefinitionCommandHandlerTests
{
    private static CreatePeWorkflowDefinitionCommand BuildCmd(
        PurchaseEvaluationType type = PurchaseEvaluationType.DuyetNcc,
        string code = "QT-DN-A-TEST",
        string name = "Test Workflow")
    {
        return new CreatePeWorkflowDefinitionCommand(
            EvaluationType: type,
            Code: code,
            Name: name,
            Description: null,
            Steps: new List<CreatePeWorkflowStepInput>
            {
                new(Order: 1, Phase: (int)PurchaseEvaluationPhase.ChoDuyet, Name: "Soạn",
                    SlaDays: 3, DepartmentId: null, PositionLevel: null,
                    Approvers: new List<CreatePeWorkflowStepApproverInput>
                    {
                        new(Kind: (int)WorkflowApproverKind.Role, AssignmentValue: AppRoles.Drafter),
                    }),
                new(Order: 2, Phase: (int)PurchaseEvaluationPhase.ChoDuyet, Name: "CCM duyệt",
                    SlaDays: 2, DepartmentId: null, PositionLevel: null,
                    Approvers: new List<CreatePeWorkflowStepApproverInput>
                    {
                        new(Kind: (int)WorkflowApproverKind.Role, AssignmentValue: AppRoles.CostControl),
                    }),
            });
    }

    [Fact]
    public async Task Create_FirstVersion_PersistsWith_Version1_And_IsActiveTrue()
    {
        using var fix = new SqliteDbFixture();
        var handler = new CreatePeWorkflowDefinitionCommandHandler(fix.Db);

        var id = await handler.Handle(BuildCmd(), CancellationToken.None);

        var def = fix.Db.PurchaseEvaluationWorkflowDefinitions
            .Where(d => d.Id == id)
            .Single();
        def.Version.Should().Be(1);
        def.IsActive.Should().BeTrue();
        def.ActivatedAt.Should().NotBeNull();
        def.Code.Should().Be("QT-DN-A-TEST");
    }

    [Fact]
    public async Task Create_SecondVersionSameCode_AutoIncrements_AndDeactivatesPrevious()
    {
        using var fix = new SqliteDbFixture();
        var handler = new CreatePeWorkflowDefinitionCommandHandler(fix.Db);

        var id1 = await handler.Handle(BuildCmd(name: "v1"), CancellationToken.None);
        var id2 = await handler.Handle(BuildCmd(name: "v2"), CancellationToken.None);

        var def1 = fix.Db.PurchaseEvaluationWorkflowDefinitions.Single(d => d.Id == id1);
        var def2 = fix.Db.PurchaseEvaluationWorkflowDefinitions.Single(d => d.Id == id2);

        def1.IsActive.Should().BeFalse("Version cũ phải bị deactivate khi tạo version mới");
        def1.Version.Should().Be(1);

        def2.IsActive.Should().BeTrue();
        def2.Version.Should().Be(2);
    }

    [Fact]
    public async Task Create_DifferentEvaluationType_DoesNotAffect_Other()
    {
        using var fix = new SqliteDbFixture();
        var handler = new CreatePeWorkflowDefinitionCommandHandler(fix.Db);

        // Type A active
        var idA = await handler.Handle(
            BuildCmd(type: PurchaseEvaluationType.DuyetNcc, code: "QT-DN-A"),
            CancellationToken.None);

        // Type B active — không được tắt Type A
        var idB = await handler.Handle(
            BuildCmd(type: PurchaseEvaluationType.DuyetNccPhuongAn, code: "QT-DN-B"),
            CancellationToken.None);

        var defA = fix.Db.PurchaseEvaluationWorkflowDefinitions.Single(d => d.Id == idA);
        var defB = fix.Db.PurchaseEvaluationWorkflowDefinitions.Single(d => d.Id == idB);

        defA.IsActive.Should().BeTrue("Type A không liên quan tới Type B");
        defB.IsActive.Should().BeTrue();
    }

    [Fact]
    public async Task Create_PersistsAllSteps_OrderedByOrderField()
    {
        using var fix = new SqliteDbFixture();
        var handler = new CreatePeWorkflowDefinitionCommandHandler(fix.Db);

        var id = await handler.Handle(BuildCmd(), CancellationToken.None);

        var steps = fix.Db.PurchaseEvaluationWorkflowSteps
            .Where(s => s.PurchaseEvaluationWorkflowDefinitionId == id)
            .OrderBy(s => s.Order)
            .ToList();

        steps.Should().HaveCount(2);
        steps[0].Order.Should().Be(1);
        steps[0].Phase.Should().Be(PurchaseEvaluationPhase.ChoDuyet);
        steps[0].Name.Should().Be("Soạn");
        steps[1].Order.Should().Be(2);
        steps[1].Phase.Should().Be(PurchaseEvaluationPhase.ChoDuyet);
    }

    [Fact]
    public async Task Create_PersistsApprovers_PerStep()
    {
        using var fix = new SqliteDbFixture();
        var handler = new CreatePeWorkflowDefinitionCommandHandler(fix.Db);

        var id = await handler.Handle(BuildCmd(), CancellationToken.None);

        var stepIds = fix.Db.PurchaseEvaluationWorkflowSteps
            .Where(s => s.PurchaseEvaluationWorkflowDefinitionId == id)
            .Select(s => s.Id)
            .ToList();
        var approvers = fix.Db.PurchaseEvaluationWorkflowStepApprovers
            .Where(a => stepIds.Contains(a.PurchaseEvaluationWorkflowStepId))
            .ToList();

        approvers.Should().HaveCount(2);
        approvers.Should().Contain(a => a.Kind == WorkflowApproverKind.Role
            && a.AssignmentValue == AppRoles.Drafter);
        approvers.Should().Contain(a => a.Kind == WorkflowApproverKind.Role
            && a.AssignmentValue == AppRoles.CostControl);
    }

    [Fact]
    public async Task Create_ThirdVersion_DeactivatesV2_Increments_To_V3()
    {
        // Tránh edge case: deactivate logic có gặp v2 active không, hay vẫn xét v1?
        using var fix = new SqliteDbFixture();
        var handler = new CreatePeWorkflowDefinitionCommandHandler(fix.Db);

        await handler.Handle(BuildCmd(name: "v1"), CancellationToken.None);
        await handler.Handle(BuildCmd(name: "v2"), CancellationToken.None);
        var id3 = await handler.Handle(BuildCmd(name: "v3"), CancellationToken.None);

        var allDefs = fix.Db.PurchaseEvaluationWorkflowDefinitions
            .Where(d => d.Code == "QT-DN-A-TEST")
            .OrderBy(d => d.Version)
            .ToList();

        allDefs.Should().HaveCount(3);
        allDefs[0].Version.Should().Be(1);
        allDefs[0].IsActive.Should().BeFalse();
        allDefs[1].Version.Should().Be(2);
        allDefs[1].IsActive.Should().BeFalse();
        allDefs[2].Version.Should().Be(3);
        allDefs[2].IsActive.Should().BeTrue();
        allDefs[2].Id.Should().Be(id3);
    }
}
