using SolutionErp.Domain.Budgets;
using SolutionErp.Domain.Identity;

namespace SolutionErp.Domain.Tests.Budgets;

// Tests cho BudgetPolicy (hardcoded simple 3-step Default).
// Chống regression khi BudgetPhase enum thêm phase hoặc role mapping bị edit.

public class BudgetPolicyTests
{
    [Fact]
    public void Default_Drafter_DangSoanThao_To_ChoCCM_Allowed()
    {
        BudgetPolicies.Default
            .IsTransitionAllowed(BudgetPhase.DangSoanThao, BudgetPhase.ChoCCM,
                [AppRoles.Drafter])
            .Should().BeTrue();
    }

    [Fact]
    public void Default_DeptManager_DangSoanThao_To_ChoCCM_Allowed()
    {
        BudgetPolicies.Default
            .IsTransitionAllowed(BudgetPhase.DangSoanThao, BudgetPhase.ChoCCM,
                [AppRoles.DeptManager])
            .Should().BeTrue();
    }

    [Fact]
    public void Default_RandomRole_DangSoanThao_To_ChoCCM_Denied()
    {
        BudgetPolicies.Default
            .IsTransitionAllowed(BudgetPhase.DangSoanThao, BudgetPhase.ChoCCM,
                [AppRoles.Procurement])
            .Should().BeFalse();
    }

    [Fact]
    public void Default_CostControl_ChoCCM_To_ChoCEO_Allowed()
    {
        BudgetPolicies.Default
            .IsTransitionAllowed(BudgetPhase.ChoCCM, BudgetPhase.ChoCEO,
                [AppRoles.CostControl])
            .Should().BeTrue();
    }

    [Fact]
    public void Default_CostControl_ChoCCM_To_DangSoanThao_Allowed()
    {
        // Trả về Drafter
        BudgetPolicies.Default
            .IsTransitionAllowed(BudgetPhase.ChoCCM, BudgetPhase.DangSoanThao,
                [AppRoles.CostControl])
            .Should().BeTrue();
    }

    [Fact]
    public void Default_Director_ChoCEO_To_DaDuyet_Allowed()
    {
        BudgetPolicies.Default
            .IsTransitionAllowed(BudgetPhase.ChoCEO, BudgetPhase.DaDuyet,
                [AppRoles.Director])
            .Should().BeTrue();

        BudgetPolicies.Default
            .IsTransitionAllowed(BudgetPhase.ChoCEO, BudgetPhase.DaDuyet,
                [AppRoles.AuthorizedSigner])
            .Should().BeTrue();
    }

    [Fact]
    public void Default_CCM_Cannot_Approve_To_DaDuyet()
    {
        // CCM chỉ chuyển đến ChoCEO, không tự duyệt thành DaDuyet
        BudgetPolicies.Default
            .IsTransitionAllowed(BudgetPhase.ChoCEO, BudgetPhase.DaDuyet,
                [AppRoles.CostControl])
            .Should().BeFalse();
    }

    [Fact]
    public void Default_DaDuyet_NoFurtherTransitions()
    {
        BudgetPolicies.Default.NextPhasesFrom(BudgetPhase.DaDuyet)
            .Should().BeEmpty("DaDuyet là terminal");
    }

    [Fact]
    public void Default_TuChoi_NoFurtherTransitions()
    {
        BudgetPolicies.Default.NextPhasesFrom(BudgetPhase.TuChoi)
            .Should().BeEmpty("TuChoi là terminal");
    }

    [Fact]
    public void Default_ActivePhases_Includes_All5States()
    {
        BudgetPolicies.Default.ActivePhases.Should().BeEquivalentTo(new[]
        {
            BudgetPhase.DangSoanThao, BudgetPhase.ChoCCM,
            BudgetPhase.ChoCEO, BudgetPhase.DaDuyet, BudgetPhase.TuChoi,
        });
    }

    [Fact]
    public void Default_NextPhasesFrom_DangSoanThao_Includes_ChoCCM_And_TuChoi()
    {
        var next = BudgetPolicies.Default.NextPhasesFrom(BudgetPhase.DangSoanThao);
        next.Should().Contain(BudgetPhase.ChoCCM);
        next.Should().Contain(BudgetPhase.TuChoi);
    }

    [Fact]
    public void Default_NextPhasesFrom_ChoCEO_Includes_DaDuyet_And_DangSoanThao()
    {
        var next = BudgetPolicies.Default.NextPhasesFrom(BudgetPhase.ChoCEO);
        next.Should().Contain(BudgetPhase.DaDuyet);
        next.Should().Contain(BudgetPhase.DangSoanThao);
    }

    // SLA — chống regression khi đổi phase deadline accidentally
    [Fact]
    public void Default_SlaDeadlines_Match_Spec()
    {
        BudgetPolicies.Default.PhaseSla[BudgetPhase.DangSoanThao]
            .Should().Be(TimeSpan.FromDays(5));
        BudgetPolicies.Default.PhaseSla[BudgetPhase.ChoCCM]
            .Should().Be(TimeSpan.FromDays(3));
        BudgetPolicies.Default.PhaseSla[BudgetPhase.ChoCEO]
            .Should().Be(TimeSpan.FromDays(2));
        BudgetPolicies.Default.PhaseSla[BudgetPhase.DaDuyet]
            .Should().BeNull("Terminal phase không có SLA");
    }
}
