using SolutionErp.Domain.Contracts;
using SolutionErp.Domain.Identity;

namespace SolutionErp.Domain.Tests.Contracts;

// Tests for WorkflowPolicy state machine — pure functions, no DB / IO.
// Mục tiêu: chống regression khi policy table bị edit nhầm hoặc khi ContractPhase
// enum thêm phase mới mà quên update policy. ALL fast in-memory.

public class WorkflowPolicyTests
{
    // ===== Standard policy (HĐ Thầu phụ / NCC / Giao khoán — full CCM) =====

    [Fact]
    public void Standard_Drafter_DangSoanThao_To_DangGopY_Allowed()
    {
        WorkflowPolicies.Standard
            .IsTransitionAllowed(ContractPhase.DangSoanThao, ContractPhase.DangGopY,
                [AppRoles.Drafter])
            .Should().BeTrue();
    }

    [Fact]
    public void Standard_DeptManager_DangSoanThao_To_DangGopY_Allowed()
    {
        WorkflowPolicies.Standard
            .IsTransitionAllowed(ContractPhase.DangSoanThao, ContractPhase.DangGopY,
                [AppRoles.DeptManager])
            .Should().BeTrue();
    }

    [Fact]
    public void Standard_RandomRole_DangSoanThao_To_DangGopY_Denied()
    {
        WorkflowPolicies.Standard
            .IsTransitionAllowed(ContractPhase.DangSoanThao, ContractPhase.DangGopY,
                [AppRoles.Procurement])
            .Should().BeFalse();
    }

    [Fact]
    public void Standard_HasCcmPhase_InActivePhases()
    {
        WorkflowPolicies.Standard.HasPhase(ContractPhase.DangKiemTraCCM)
            .Should().BeTrue("Standard policy phải có CCM phase");
    }

    [Fact]
    public void Standard_CcmRole_DangKiemTraCCM_To_DangTrinhKy_Allowed()
    {
        WorkflowPolicies.Standard
            .IsTransitionAllowed(ContractPhase.DangKiemTraCCM, ContractPhase.DangTrinhKy,
                [AppRoles.CostControl])
            .Should().BeTrue();
    }

    [Fact]
    public void Standard_DangTrinhKy_To_DangDongDau_RequiresDirectorOrSigner()
    {
        WorkflowPolicies.Standard
            .IsTransitionAllowed(ContractPhase.DangTrinhKy, ContractPhase.DangDongDau,
                [AppRoles.Director])
            .Should().BeTrue();

        WorkflowPolicies.Standard
            .IsTransitionAllowed(ContractPhase.DangTrinhKy, ContractPhase.DangDongDau,
                [AppRoles.AuthorizedSigner])
            .Should().BeTrue();

        WorkflowPolicies.Standard
            .IsTransitionAllowed(ContractPhase.DangTrinhKy, ContractPhase.DangDongDau,
                [AppRoles.CostControl])
            .Should().BeFalse();
    }

    [Fact]
    public void Standard_HrAdmin_DangDongDau_To_DaPhatHanh_Allowed()
    {
        WorkflowPolicies.Standard
            .IsTransitionAllowed(ContractPhase.DangDongDau, ContractPhase.DaPhatHanh,
                [AppRoles.HrAdmin])
            .Should().BeTrue();
    }

    [Fact]
    public void Standard_FromTerminal_DaPhatHanh_NoFurtherTransitions()
    {
        WorkflowPolicies.Standard.NextPhasesFrom(ContractPhase.DaPhatHanh)
            .Should().BeEmpty("DaPhatHanh là terminal — không transition tiếp");
    }

    [Fact]
    public void Standard_RejectFromCCM_GoesTo_TraLai()
    {
        // Session 17 spec: Trả lại = Phase riêng (TraLai), không revert DangSoanThao
        WorkflowPolicies.Standard
            .IsTransitionAllowed(ContractPhase.DangKiemTraCCM, ContractPhase.TraLai,
                [AppRoles.CostControl])
            .Should().BeTrue("CCM có quyền reject về TraLai");
    }

    [Fact]
    public void Standard_TraLai_To_DangGopY_Allowed_For_Drafter()
    {
        // Drafter từ TraLai gửi lại = entry point thứ 2 (mirror DangSoanThao → DangGopY)
        WorkflowPolicies.Standard
            .IsTransitionAllowed(ContractPhase.TraLai, ContractPhase.DangGopY,
                [AppRoles.Drafter])
            .Should().BeTrue("Drafter resubmit từ Trả lại");
    }

    [Fact]
    public void Standard_NextPhasesFrom_Draft_Includes_DangGopY_And_TuChoi()
    {
        var next = WorkflowPolicies.Standard.NextPhasesFrom(ContractPhase.DangSoanThao);
        next.Should().Contain(ContractPhase.DangGopY);
        next.Should().Contain(ContractPhase.TuChoi);
    }

    // ===== SkipCcm policy (HĐ Dịch vụ / Mua bán / Nguyên tắc — bỏ phase CCM) =====

    [Fact]
    public void SkipCcm_DoesNotHave_DangKiemTraCCM_Phase()
    {
        WorkflowPolicies.SkipCcm.HasPhase(ContractPhase.DangKiemTraCCM)
            .Should().BeFalse("SkipCcm policy bypass CCM phase");
    }

    [Fact]
    public void SkipCcm_DangInKy_GoesDirectlyTo_DangTrinhKy()
    {
        WorkflowPolicies.SkipCcm
            .IsTransitionAllowed(ContractPhase.DangInKy, ContractPhase.DangTrinhKy,
                [AppRoles.Drafter])
            .Should().BeTrue();
    }

    [Fact]
    public void SkipCcm_NoTransition_To_DangKiemTraCCM()
    {
        WorkflowPolicies.SkipCcm
            .IsTransitionAllowed(ContractPhase.DangInKy, ContractPhase.DangKiemTraCCM,
                [AppRoles.Drafter])
            .Should().BeFalse();
    }

    // ===== Registry mapping per ContractType =====

    [Theory]
    [InlineData(ContractType.HopDongThauPhu, "Standard")]
    [InlineData(ContractType.HopDongGiaoKhoan, "Standard")]
    [InlineData(ContractType.HopDongNhaCungCap, "Standard")]
    [InlineData(ContractType.HopDongDichVu, "SkipCcm")]
    [InlineData(ContractType.HopDongMuaBan, "SkipCcm")]
    [InlineData(ContractType.HopDongNguyenTacNCC, "SkipCcm")]
    [InlineData(ContractType.HopDongNguyenTacDichVu, "SkipCcm")]
    public void Registry_DefaultPolicyName_MapsCorrectly(ContractType type, string expectedName)
    {
        WorkflowPolicyRegistry.DefaultPolicyNameFor(type)
            .Should().Be(expectedName);
    }

    [Fact]
    public void Registry_ForContract_BypassFlag_OverridesPolicy()
    {
        var contract = new Contract
        {
            Type = ContractType.HopDongThauPhu,   // mặc định Standard
            BypassProcurementAndCCM = true,        // override → SkipCcm
        };
        WorkflowPolicyRegistry.ForContract(contract).Name
            .Should().Be("SkipCcm");
    }

    // ===== FromDefinition (versioned admin-authored) =====

    [Fact]
    public void FromDefinition_BuildsPolicy_FromOrderedSteps()
    {
        var def = new WorkflowDefinition
        {
            Code = "QT-TEST",
            Version = 1,
            Name = "Test workflow",
            ContractType = ContractType.HopDongMuaBan,
            Steps =
            [
                new WorkflowStep { Order = 1, Phase = ContractPhase.DangSoanThao, Name = "Soạn",
                    Approvers = [new WorkflowStepApprover { Kind = WorkflowApproverKind.Role, AssignmentValue = AppRoles.Drafter }] },
                new WorkflowStep { Order = 2, Phase = ContractPhase.DangGopY, Name = "Góp ý",
                    Approvers = [new WorkflowStepApprover { Kind = WorkflowApproverKind.Role, AssignmentValue = AppRoles.ProjectManager }] },
                new WorkflowStep { Order = 3, Phase = ContractPhase.DaPhatHanh, Name = "Phát hành",
                    Approvers = [new WorkflowStepApprover { Kind = WorkflowApproverKind.Role, AssignmentValue = AppRoles.HrAdmin }] },
            ],
        };
        var policy = WorkflowPolicyRegistry.FromDefinition(def);

        policy.Name.Should().Be("QT-TEST-v01");
        policy.IsTransitionAllowed(ContractPhase.DangSoanThao, ContractPhase.DangGopY, [AppRoles.ProjectManager])
            .Should().BeTrue();
        policy.IsTransitionAllowed(ContractPhase.DangGopY, ContractPhase.DaPhatHanh, [AppRoles.HrAdmin])
            .Should().BeTrue();
        policy.HasPhase(ContractPhase.TuChoi).Should().BeTrue("TuChoi luôn auto-thêm vào ActivePhases");
    }

    [Fact]
    public void FromDefinition_UserKindApprover_PopulatesUserTransitions()
    {
        var userId = Guid.NewGuid().ToString();
        var def = new WorkflowDefinition
        {
            Code = "QT-TEST",
            Version = 1,
            Name = "Test workflow user-kind",
            ContractType = ContractType.HopDongMuaBan,
            Steps =
            [
                new WorkflowStep { Order = 1, Phase = ContractPhase.DangSoanThao, Name = "Soạn", Approvers = [] },
                new WorkflowStep { Order = 2, Phase = ContractPhase.DangGopY, Name = "Góp ý",
                    Approvers = [new WorkflowStepApprover { Kind = WorkflowApproverKind.User, AssignmentValue = userId }] },
            ],
        };
        var policy = WorkflowPolicyRegistry.FromDefinition(def);

        // Role nào cũng deny vì step 2 chỉ có User-kind
        policy.IsTransitionAllowed(ContractPhase.DangSoanThao, ContractPhase.DangGopY,
                [AppRoles.Drafter])
            .Should().BeFalse();
        // Đúng user-id → allow
        policy.IsTransitionAllowed(ContractPhase.DangSoanThao, ContractPhase.DangGopY,
                [AppRoles.Drafter], Guid.Parse(userId))
            .Should().BeTrue();
        // Sai user-id → deny
        policy.IsTransitionAllowed(ContractPhase.DangSoanThao, ContractPhase.DangGopY,
                [AppRoles.Drafter], Guid.NewGuid())
            .Should().BeFalse();
    }
}
