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_GoesTo_TraLai(string policyName)
    {
        // Session 17 spec: Trả lại = Phase riêng (TraLai), không revert DangSoanThao
        var policy = policyName == nameof(PurchaseEvaluationPolicies.NccOnly)
            ? PurchaseEvaluationPolicies.NccOnly
            : PurchaseEvaluationPolicies.NccWithPlan;

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

    [Theory]
    [InlineData(nameof(PurchaseEvaluationPolicies.NccOnly))]
    [InlineData(nameof(PurchaseEvaluationPolicies.NccWithPlan))]
    public void BothPolicies_TraLai_To_ChoPurchasing_AllowedForDrafter(string policyName)
    {
        // Drafter từ TraLai gửi lại = entry point thứ 2 (mirror DangSoanThao)
        var policy = policyName == nameof(PurchaseEvaluationPolicies.NccOnly)
            ? PurchaseEvaluationPolicies.NccOnly
            : PurchaseEvaluationPolicies.NccWithPlan;

        policy.IsTransitionAllowed(PurchaseEvaluationPhase.TraLai, PurchaseEvaluationPhase.ChoPurchasing,
                [AppRoles.Drafter])
            .Should().BeTrue();
    }

    // UAT S60 (anh Kiệt 14:14): "bỏ luôn nút Từ chối — Duyệt hoặc Trả về thôi".
    // Spec change: TuChoi GỠ khỏi MỌI transition map (trước đó Drafter/DeptManager
    // được TuChoi từ Nháp/TraLai + approver TuChoi từ phase trung gian).
    [Theory]
    [InlineData(nameof(PurchaseEvaluationPolicies.NccOnly))]
    [InlineData(nameof(PurchaseEvaluationPolicies.NccWithPlan))]
    public void BothPolicies_TuChoi_RemovedFromAllTransitions_S60(string policyName)
    {
        var policy = policyName == nameof(PurchaseEvaluationPolicies.NccOnly)
            ? PurchaseEvaluationPolicies.NccOnly
            : PurchaseEvaluationPolicies.NccWithPlan;

        // Không role nào TuChoi được nữa — kể cả Drafter/DeptManager (huỷ phiếu
        // nháp = nút Xóa riêng) lẫn approver phase trung gian.
        policy.IsTransitionAllowed(PurchaseEvaluationPhase.DangSoanThao, PurchaseEvaluationPhase.TuChoi,
                [AppRoles.Drafter, AppRoles.DeptManager])
            .Should().BeFalse();
        policy.IsTransitionAllowed(PurchaseEvaluationPhase.TraLai, PurchaseEvaluationPhase.TuChoi,
                [AppRoles.Drafter, AppRoles.DeptManager])
            .Should().BeFalse();
        policy.IsTransitionAllowed(PurchaseEvaluationPhase.ChoPurchasing, PurchaseEvaluationPhase.TuChoi,
                [AppRoles.Procurement])
            .Should().BeFalse();

        // NextPhases (nguồn nút FE) không bao giờ chứa TuChoi nữa.
        foreach (var phase in policy.ActivePhases)
            policy.NextPhasesFrom(phase).Should().NotContain(PurchaseEvaluationPhase.TuChoi);
    }

    [Fact]
    public void V2SchemaPolicy_TuChoi_RemovedFromAllTransitions_S60()
    {
        var policy = PurchaseEvaluationPolicyRegistry.ForV2Schema();

        policy.IsTransitionAllowed(PurchaseEvaluationPhase.ChoDuyet, PurchaseEvaluationPhase.TuChoi,
                [AppRoles.Drafter, AppRoles.DeptManager, AppRoles.Director])
            .Should().BeFalse();
        foreach (var phase in policy.ActivePhases)
            policy.NextPhasesFrom(phase).Should().NotContain(PurchaseEvaluationPhase.TuChoi);

        // 2 hành động còn lại giữ nguyên: trình + duyệt/trả lại.
        policy.NextPhasesFrom(PurchaseEvaluationPhase.DangSoanThao)
            .Should().Contain(PurchaseEvaluationPhase.ChoDuyet);
        policy.NextPhasesFrom(PurchaseEvaluationPhase.ChoDuyet)
            .Should().Contain(PurchaseEvaluationPhase.TraLai);
    }

    // ===== 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");
    }
}
