using Baya.Application.Common;
using Baya.Domain.Entities.Identity;
using Baya.Domain.Entities.Verification;
using static Baya.Test.Foundation.Verification.VerificationTestSupport;

namespace Baya.Test.Foundation.Verification;

public class VerificationAggregatorTests
{
    private static readonly DateTimeOffset Now = new(2026, 7, 1, 12, 0, 0, TimeSpan.Zero);

    private static (NurseVerification Verification, NurseProfile Profile) Build(params VerificationStepStatus[] statuses)
    {
        var verification = new NurseVerification { NurseId = 42, Status = VerificationStatus.Pending };
        for (var i = 0; i < statuses.Length; i++)
            verification.Steps.Add(Step(i + 1, StepType(i + 1, $"step_{i}", automated: false), statuses[i]));

        return (verification, new NurseProfile());
    }

    [Fact]
    public void Finalize_AllPassed_ApprovesAndFlipsVerified()
    {
        var (verification, profile) = Build(VerificationStepStatus.Passed, VerificationStepStatus.Passed);

        var status = VerificationAggregator.Finalize(verification, profile, Now);

        Assert.Equal(VerificationStatus.Approved, status);
        Assert.Equal(VerificationStatus.Approved, verification.Status);
        Assert.Equal(Now, verification.ApprovedAt);
        Assert.True(profile.IsVerified);
    }

    [Fact]
    public void Finalize_OneFailed_RejectsAndKeepsUnverified()
    {
        var (verification, profile) = Build(VerificationStepStatus.Passed, VerificationStepStatus.Failed);

        VerificationAggregator.Finalize(verification, profile, Now);

        Assert.Equal(VerificationStatus.Rejected, verification.Status);
        Assert.Equal(Now, verification.RejectedAt);
        Assert.Null(verification.ApprovedAt);
        Assert.False(profile.IsVerified);
    }

    [Fact]
    public void Finalize_OneInReview_SetsInReview()
    {
        var (verification, profile) = Build(VerificationStepStatus.Passed, VerificationStepStatus.InReview);

        VerificationAggregator.Finalize(verification, profile, Now);

        Assert.Equal(VerificationStatus.InReview, verification.Status);
        Assert.False(profile.IsVerified);
    }

    [Fact]
    public void Finalize_AllPending_StaysPending()
    {
        var (verification, profile) = Build(VerificationStepStatus.Pending, VerificationStepStatus.Pending);

        VerificationAggregator.Finalize(verification, profile, Now);

        Assert.Equal(VerificationStatus.Pending, verification.Status);
        Assert.False(profile.IsVerified);
    }

    [Fact]
    public void Finalize_PreviouslyApproved_ThenExpires_ReversesVerified()
    {
        var (verification, profile) = Build(VerificationStepStatus.Passed, VerificationStepStatus.Passed);
        VerificationAggregator.Finalize(verification, profile, Now);
        Assert.True(profile.IsVerified);

        // A required step lapses (the expiry scan) → re-gate.
        verification.Steps.Last().Status = VerificationStepStatus.Expired;
        VerificationAggregator.Finalize(verification, profile, Now);

        Assert.False(profile.IsVerified);
        Assert.Equal(VerificationStatus.Pending, verification.Status);
        Assert.Null(verification.ApprovedAt);
    }

    [Fact]
    public void Finalize_Suspended_StaysSuspendedAndUnverified()
    {
        var (verification, profile) = Build(VerificationStepStatus.Passed, VerificationStepStatus.Passed);
        profile.MarkVerified();
        verification.Status = VerificationStatus.Suspended;

        var status = VerificationAggregator.Finalize(verification, profile, Now);

        Assert.Equal(VerificationStatus.Suspended, status);
        Assert.False(profile.IsVerified);
    }

    [Fact]
    public void Finalize_NoSteps_DoesNotApprove()
    {
        var verification = new NurseVerification { NurseId = 42, Status = VerificationStatus.Pending };
        var profile = new NurseProfile();

        VerificationAggregator.Finalize(verification, profile, Now);

        Assert.False(profile.IsVerified);
        Assert.Equal(VerificationStatus.Pending, verification.Status);
    }

    [Fact]
    public void BlockingStepCodes_ReturnsCodesOfNonPassedSteps()
    {
        var (verification, _) = Build(VerificationStepStatus.Passed, VerificationStepStatus.Pending);

        var blocking = VerificationAggregator.BlockingStepCodes(verification.Steps);

        Assert.Single(blocking);
        Assert.Equal("step_1", blocking[0]);
    }
}
