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

namespace IamService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for AccessRequest aggregate.
/// VI: Repository implementation cho AccessRequest aggregate.
/// </summary>
public class AccessRequestRepository : IAccessRequestRepository
{
    private readonly IamServiceContext _context;

    public IUnitOfWork UnitOfWork => _context;

    public AccessRequestRepository(IamServiceContext context)
    {
        _context = context;
    }

    public AccessRequest Add(AccessRequest request)
    {
        return _context.AccessRequests.Add(request).Entity;
    }

    public void Update(AccessRequest request)
    {
        _context.Entry(request).State = EntityState.Modified;
    }

    public async Task<AccessRequest?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.AccessRequests
            .FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
    }

    public async Task<AccessRequest?> GetByIdWithApproversAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.AccessRequests
            .Include(x => x.Approvers)
            .FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
    }

    public async Task<IEnumerable<AccessRequest>> GetByRequesterIdAsync(
        Guid requesterId, 
        CancellationToken cancellationToken = default)
    {
        return await _context.AccessRequests
            .Include(x => x.Approvers)
            .Where(x => EF.Property<Guid>(x, "_requesterId") == requesterId)
            .OrderByDescending(x => EF.Property<DateTime>(x, "_createdAt"))
            .ToListAsync(cancellationToken);
    }

    public async Task<IEnumerable<AccessRequest>> GetPendingByApproverIdAsync(
        Guid approverId, 
        CancellationToken cancellationToken = default)
    {
        return await _context.AccessRequests
            .Include(x => x.Approvers)
            .Where(x => x.Approvers.Any(a => 
                EF.Property<Guid>(a, "_userId") == approverId && 
                EF.Property<ApproverStatus>(a, "_status") == ApproverStatus.Pending))
            .Where(x => EF.Property<AccessRequestStatus>(x, "_status") == AccessRequestStatus.Pending)
            .OrderByDescending(x => EF.Property<DateTime>(x, "_createdAt"))
            .ToListAsync(cancellationToken);
    }

    public async Task<IEnumerable<AccessRequest>> GetExpiredRequestsAsync(CancellationToken cancellationToken = default)
    {
        var now = DateTime.UtcNow;
        return await _context.AccessRequests
            .Where(x => EF.Property<AccessRequestStatus>(x, "_status") == AccessRequestStatus.Pending)
            .Where(x => EF.Property<DateTime?>(x, "_expiresAt") < now)
            .ToListAsync(cancellationToken);
    }
}
