using Microsoft.EntityFrameworkCore;
using IamService.Domain.AggregatesModel.VerificationAggregate;
using IamService.Domain.SeedWork;

namespace IamService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for IdentityVerification aggregate.
/// VI: Repository implementation cho IdentityVerification aggregate.
/// </summary>
public class IdentityVerificationRepository : IIdentityVerificationRepository
{
    private readonly IamServiceContext _context;

    public IUnitOfWork UnitOfWork => _context;

    public IdentityVerificationRepository(IamServiceContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    /// <inheritdoc />
    public async Task<IdentityVerification?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.IdentityVerifications
            .FirstOrDefaultAsync(v => v.Id == id, cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IEnumerable<IdentityVerification>> GetByUserIdAsync(Guid userId, CancellationToken cancellationToken = default)
    {
        return await _context.IdentityVerifications
            .Where(v => EF.Property<Guid>(v, "_userId") == userId)
            .OrderByDescending(v => EF.Property<DateTime>(v, "_requestedAt"))
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IdentityVerification?> GetActiveByUserIdAndTypeAsync(
        Guid userId,
        VerificationType type,
        CancellationToken cancellationToken = default)
    {
        return await _context.IdentityVerifications
            .Where(v =>
                EF.Property<Guid>(v, "_userId") == userId &&
                v.TypeId == type.Id &&
                (v.StatusId == VerificationStatus.Pending.Id || v.StatusId == VerificationStatus.InProgress.Id) &&
                EF.Property<DateTime>(v, "_expiresAt") > DateTime.UtcNow)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IdentityVerification?> GetLatestByUserIdAndTypeAsync(
        Guid userId,
        VerificationType type,
        CancellationToken cancellationToken = default)
    {
        return await _context.IdentityVerifications
            .Where(v =>
                EF.Property<Guid>(v, "_userId") == userId &&
                v.TypeId == type.Id)
            .OrderByDescending(v => EF.Property<DateTime>(v, "_requestedAt"))
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<bool> HasVerifiedAsync(Guid userId, VerificationType type, CancellationToken cancellationToken = default)
    {
        return await _context.IdentityVerifications
            .AnyAsync(v =>
                EF.Property<Guid>(v, "_userId") == userId &&
                v.TypeId == type.Id &&
                v.StatusId == VerificationStatus.Verified.Id,
                cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IEnumerable<IdentityVerification>> GetExpiredPendingAsync(CancellationToken cancellationToken = default)
    {
        return await _context.IdentityVerifications
            .Where(v =>
                (v.StatusId == VerificationStatus.Pending.Id || v.StatusId == VerificationStatus.InProgress.Id) &&
                EF.Property<DateTime>(v, "_expiresAt") < DateTime.UtcNow)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public IdentityVerification Add(IdentityVerification verification)
    {
        return _context.IdentityVerifications.Add(verification).Entity;
    }

    /// <inheritdoc />
    public void Update(IdentityVerification verification)
    {
        _context.Entry(verification).State = EntityState.Modified;
    }
}
