#nullable enable
using Baya.Domain.Entities.Identity;
using Baya.Domain.Entities.Verification;

namespace Baya.Application.Common;

/// <summary>
/// The single place that rolls per-step outcomes into <see cref="NurseVerification.Status"/> and drives the
/// guarded <c>nurse_profiles.is_verified</c> flip. It mutates the <b>tracked</b> verification + profile
/// in place; the caller commits once, so the status change and the <c>is_verified</c> flip land in the same
/// transaction — there is never an in-between state where the verification is approved but the nurse is not
/// yet bookable (or vice-versa).
///
/// Rules (steps seeded on submit are exactly the active required steps, so "all steps" == "all required"):
/// approved only when every step passed; rejected if any step failed; in_review if any step awaits an admin;
/// else pending. Suspension is terminal here — an already-suspended verification is not auto-recovered.
/// </summary>
public static class VerificationAggregator
{
    public static VerificationStatus Finalize(NurseVerification verification, NurseProfile profile, DateTimeOffset now)
    {
        // Suspension is an explicit admin state; the scanner/automation must not silently un-suspend a nurse.
        if (verification.Status == VerificationStatus.Suspended)
        {
            profile.MarkUnverified();
            return verification.Status;
        }

        var steps = verification.Steps;
        var hasSteps = steps.Count > 0;
        var anyFailed = steps.Any(s => s.Status == VerificationStepStatus.Failed);
        var anyInReview = steps.Any(s => s.Status == VerificationStepStatus.InReview);
        var allPassed = hasSteps && steps.All(s => s.Status == VerificationStepStatus.Passed);

        if (allPassed)
        {
            if (verification.Status != VerificationStatus.Approved)
            {
                verification.Status = VerificationStatus.Approved;
                verification.ApprovedAt = now;
                verification.RejectedAt = null;
                verification.RejectionReason = null;
            }

            profile.MarkVerified();
            return VerificationStatus.Approved;
        }

        // Not all required steps passed → the nurse is not bookable. Reverse the flip in the same transaction.
        profile.MarkUnverified();
        verification.ApprovedAt = null;

        if (anyFailed)
        {
            verification.Status = VerificationStatus.Rejected;
            verification.RejectedAt = now;
        }
        else if (anyInReview)
        {
            verification.Status = VerificationStatus.InReview;
        }
        else
        {
            verification.Status = VerificationStatus.Pending;
        }

        return verification.Status;
    }

    /// <summary>The codes of required steps not yet passed — the "what's blocking bookability" summary.</summary>
    public static IReadOnlyList<string> BlockingStepCodes(IEnumerable<VerificationStep> steps)
        => steps
            .Where(s => s.Status != VerificationStepStatus.Passed)
            .Select(s => s.StepType?.Code ?? string.Empty)
            .Where(c => c.Length > 0)
            .ToList();
}
