using System.Security.Claims;
using JobTrackerApi.Data;
using JobTrackerApi.Models;
using Microsoft.EntityFrameworkCore;

namespace JobTrackerApi.Services;

// The actual revocation check behind Program.cs's "local" JwtBearer OnTokenValidated. Pulled out
// of Program.cs so it's unit-testable without standing up a full TestServer/HTTP pipeline.
public static class LocalSessionValidator
{
    public static async Task<bool> IsValidAsync(JobTrackerContext db, ClaimsPrincipal? principal, DateTimeOffset now, bool requireConfirmedEmail = false, CancellationToken cancellationToken = default)
    {
        var sid = principal?.FindFirst("sid")?.Value;
        var userId = principal is null ? null : LocalAuthIdentity.GetRequiredUserId(principal);
        // Fail closed: see the comment on the OnTokenValidated wiring in Program.cs for why a
        // missing sid is rejected rather than grandfathered in.
        if (string.IsNullOrWhiteSpace(sid) || string.IsNullOrWhiteSpace(userId)) return false;

        var session = await db.UserSessions.IgnoreQueryFilters()
            .FirstOrDefaultAsync(x => x.Id == sid && x.UserId == userId, cancellationToken);
        if (session is null || session.RevokedAtUtc is not null || session.ExpiresAtUtc <= now) return false;
        var user = await db.Users.IgnoreQueryFilters().AsNoTracking().FirstOrDefaultAsync(x => x.Id == userId, cancellationToken);
        if (user is null || user.DeletionStatus != AccountDeletionStatuses.Active) return false;
        if (requireConfirmedEmail && !user.EmailConfirmed) return false;

        if (now - session.LastSeenAtUtc > TimeSpan.FromMinutes(5))
        {
            session.LastSeenAtUtc = now;
            await db.SaveChangesAsync(cancellationToken);
        }

        return true;
    }
}
