using SolutionErp.Domain.Contracts;   // WorkflowApproverKind reuse
using SolutionErp.Domain.Identity;
using SolutionErp.Domain.PurchaseEvaluations;

namespace SolutionErp.Domain.Tests.PurchaseEvaluations;

// Tests cho PurchaseEvaluationPolicy — 2 quy trình A/B chính.
// Mục tiêu: chống regression khi PEPhase thêm phase mới hoặc role mapping bị edit.

public class PurchaseEvaluationPolicyTests
{
    // ===== A — DuyetNcc (NccOnly): 3-step (Drafter → Purchasing → CCM → CEO) =====

    [Fact]
    public void NccOnly_Drafter_DangSoanThao_To_ChoPurchasing_Allowed()
    {
        PurchaseEvaluationPolicies.NccOnly
            .IsTransitionAllowed(PurchaseEvaluationPhase.DangSoanThao, PurchaseEvaluationPhase.ChoPurchasing,
                [AppRoles.Drafter])
            .Should().BeTrue();
    }

    [Fact]
    public void NccOnly_Procurement_ChoPurchasing_To_ChoCCM_Allowed()
    {
        PurchaseEvaluationPolicies.NccOnly
            .IsTransitionAllowed(PurchaseEvaluationPhase.ChoPurchasing, PurchaseEvaluationPhase.ChoCCM,
                [AppRoles.Procurement])
            .Should().BeTrue();
    }

    [Fact]
    public void NccOnly_CostControl_ChoCCM_GoesDirectlyTo_ChoCEODuyetNCC()
    {
        // A skip ChoDuAn + ChoCEODuyetPA — CCM đẩy thẳng CEO duyệt NCC
        PurchaseEvaluationPolicies.NccOnly
            .IsTransitionAllowed(PurchaseEvaluationPhase.ChoCCM, PurchaseEvaluationPhase.ChoCEODuyetNCC,
                [AppRoles.CostControl])
            .Should().BeTrue();
    }

    [Fact]
    public void NccOnly_DoesNotHave_ChoDuAn_Phase()
    {
        PurchaseEvaluationPolicies.NccOnly.HasPhase(PurchaseEvaluationPhase.ChoDuAn)
            .Should().BeFalse("Quy trình A chỉ áp dụng khi không cần Dự án duyệt");
    }

    [Fact]
    public void NccOnly_DoesNotHave_ChoCEODuyetPA_Phase()
    {
        PurchaseEvaluationPolicies.NccOnly.HasPhase(PurchaseEvaluationPhase.ChoCEODuyetPA)
            .Should().BeFalse();
    }

    [Fact]
    public void NccOnly_Director_FinalApproval_To_DaDuyet()
    {
        PurchaseEvaluationPolicies.NccOnly
            .IsTransitionAllowed(PurchaseEvaluationPhase.ChoCEODuyetNCC, PurchaseEvaluationPhase.DaDuyet,
                [AppRoles.Director])
            .Should().BeTrue();

        PurchaseEvaluationPolicies.NccOnly
            .IsTransitionAllowed(PurchaseEvaluationPhase.ChoCEODuyetNCC, PurchaseEvaluationPhase.DaDuyet,
                [AppRoles.AuthorizedSigner])
            .Should().BeTrue();
    }

    // ===== B — DuyetNccPhuongAn (NccWithPlan): 5-step =====

    [Fact]
    public void NccWithPlan_Has_ChoDuAn_AndChoCEODuyetPA_Phases()
    {
        PurchaseEvaluationPolicies.NccWithPlan.HasPhase(PurchaseEvaluationPhase.ChoDuAn)
            .Should().BeTrue();
        PurchaseEvaluationPolicies.NccWithPlan.HasPhase(PurchaseEvaluationPhase.ChoCEODuyetPA)
            .Should().BeTrue();
    }

    [Fact]
    public void NccWithPlan_Procurement_ChoPurchasing_GoesTo_ChoDuAn_NotChoCCM()
    {
        // Khác với A — B đi qua Dự án trước CCM
        PurchaseEvaluationPolicies.NccWithPlan
            .IsTransitionAllowed(PurchaseEvaluationPhase.ChoPurchasing, PurchaseEvaluationPhase.ChoDuAn,
                [AppRoles.Procurement])
            .Should().BeTrue();

        PurchaseEvaluationPolicies.NccWithPlan
            .IsTransitionAllowed(PurchaseEvaluationPhase.ChoPurchasing, PurchaseEvaluationPhase.ChoCCM,
                [AppRoles.Procurement])
            .Should().BeFalse();
    }

    [Fact]
    public void NccWithPlan_ProjectManager_ChoDuAn_To_ChoCCM_Allowed()
    {
        PurchaseEvaluationPolicies.NccWithPlan
            .IsTransitionAllowed(PurchaseEvaluationPhase.ChoDuAn, PurchaseEvaluationPhase.ChoCCM,
                [AppRoles.ProjectManager])
            .Should().BeTrue();
    }

    [Fact]
    public void NccWithPlan_CostControl_ChoCCM_GoesTo_ChoCEODuyetPA_NotDuyetNCC()
    {
        // B: CCM xong đi qua CEO duyệt PA trước, sau mới CEO duyệt NCC
        PurchaseEvaluationPolicies.NccWithPlan
            .IsTransitionAllowed(PurchaseEvaluationPhase.ChoCCM, PurchaseEvaluationPhase.ChoCEODuyetPA,
                [AppRoles.CostControl])
            .Should().BeTrue();

        PurchaseEvaluationPolicies.NccWithPlan
            .IsTransitionAllowed(PurchaseEvaluationPhase.ChoCCM, PurchaseEvaluationPhase.ChoCEODuyetNCC,
                [AppRoles.CostControl])
            .Should().BeFalse("CCM trong quy trình B không được skip CEO duyệt PA");
    }

    [Fact]
    public void NccWithPlan_Director_ChoCEODuyetPA_To_ChoCEODuyetNCC()
    {
        PurchaseEvaluationPolicies.NccWithPlan
            .IsTransitionAllowed(PurchaseEvaluationPhase.ChoCEODuyetPA, PurchaseEvaluationPhase.ChoCEODuyetNCC,
                [AppRoles.Director])
            .Should().BeTrue();
    }

    // ===== Reject paths chung cả 2 quy trình =====

    [Theory]
    [InlineData(nameof(PurchaseEvaluationPolicies.NccOnly))]
    [InlineData(nameof(PurchaseEvaluationPolicies.NccWithPlan))]
    public void BothPolicies_RejectFromCCM_GoesBackTo_DangSoanThao(string policyName)
    {
        var policy = policyName == nameof(PurchaseEvaluationPolicies.NccOnly)
            ? PurchaseEvaluationPolicies.NccOnly
            : PurchaseEvaluationPolicies.NccWithPlan;

        policy.IsTransitionAllowed(PurchaseEvaluationPhase.ChoCCM, PurchaseEvaluationPhase.DangSoanThao,
                [AppRoles.CostControl])
            .Should().BeTrue();
    }

    [Theory]
    [InlineData(nameof(PurchaseEvaluationPolicies.NccOnly))]
    [InlineData(nameof(PurchaseEvaluationPolicies.NccWithPlan))]
    public void BothPolicies_DangSoanThao_To_TuChoi_DrafterOrDeptManager(string policyName)
    {
        var policy = policyName == nameof(PurchaseEvaluationPolicies.NccOnly)
            ? PurchaseEvaluationPolicies.NccOnly
            : PurchaseEvaluationPolicies.NccWithPlan;

        policy.IsTransitionAllowed(PurchaseEvaluationPhase.DangSoanThao, PurchaseEvaluationPhase.TuChoi,
                [AppRoles.Drafter])
            .Should().BeTrue();
        policy.IsTransitionAllowed(PurchaseEvaluationPhase.DangSoanThao, PurchaseEvaluationPhase.TuChoi,
                [AppRoles.Procurement])
            .Should().BeFalse();
    }

    // ===== Registry mapping per PEType =====

    [Theory]
    [InlineData(PurchaseEvaluationType.DuyetNcc, "NccOnly")]
    [InlineData(PurchaseEvaluationType.DuyetNccPhuongAn, "NccWithPlan")]
    public void Registry_DefaultPolicyName_MapsCorrectly(
        PurchaseEvaluationType type, string expectedName)
    {
        PurchaseEvaluationPolicyRegistry.DefaultPolicyNameFor(type)
            .Should().Be(expectedName);
    }

    [Fact]
    public void Registry_For_TypeA_ReturnsNccOnlyPolicy()
    {
        PurchaseEvaluationPolicyRegistry.For(PurchaseEvaluationType.DuyetNcc).Name
            .Should().Be("NccOnly");
    }
}
