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

namespace IamService.Infrastructure.Repositories;

public class AuditLogRepository : IAuditLogRepository
{
    private readonly IamServiceContext _context;
    public IUnitOfWork UnitOfWork => _context;

    public AuditLogRepository(IamServiceContext context) => _context = context;

    public AuditLog Add(AuditLog log) => _context.AuditLogs.Add(log).Entity;

    public async Task<IEnumerable<AuditLog>> GetByActorIdAsync(Guid actorId, int take = 100, CancellationToken cancellationToken = default)
        => await _context.AuditLogs
            .Where(x => EF.Property<Guid?>(x, "_actorId") == actorId)
            .OrderByDescending(x => EF.Property<DateTime>(x, "_timestamp"))
            .Take(take)
            .ToListAsync(cancellationToken);

    public async Task<IEnumerable<AuditLog>> GetByResourceAsync(string resourceType, Guid resourceId, int take = 100, CancellationToken cancellationToken = default)
        => await _context.AuditLogs
            .Where(x => EF.Property<string>(x, "_resourceType") == resourceType && EF.Property<Guid?>(x, "_resourceId") == resourceId)
            .OrderByDescending(x => EF.Property<DateTime>(x, "_timestamp"))
            .Take(take)
            .ToListAsync(cancellationToken);

    public async Task<IEnumerable<AuditLog>> SearchAsync(
        DateTime? fromDate, DateTime? toDate,
        int? eventTypeId = null, Guid? actorId = null, string? resourceType = null,
        int skip = 0, int take = 50,
        CancellationToken cancellationToken = default)
    {
        var query = _context.AuditLogs.AsQueryable();

        if (fromDate.HasValue)
            query = query.Where(x => EF.Property<DateTime>(x, "_timestamp") >= fromDate.Value);
        if (toDate.HasValue)
            query = query.Where(x => EF.Property<DateTime>(x, "_timestamp") <= toDate.Value);
        if (eventTypeId.HasValue)
            query = query.Where(x => EF.Property<AuditEventType>(x, "_eventType").Id == eventTypeId.Value);
        if (actorId.HasValue)
            query = query.Where(x => EF.Property<Guid?>(x, "_actorId") == actorId.Value);
        if (!string.IsNullOrEmpty(resourceType))
            query = query.Where(x => EF.Property<string>(x, "_resourceType") == resourceType);

        return await query
            .OrderByDescending(x => EF.Property<DateTime>(x, "_timestamp"))
            .Skip(skip).Take(take)
            .ToListAsync(cancellationToken);
    }

    public async Task<long> GetCountAsync(DateTime? fromDate, DateTime? toDate, CancellationToken cancellationToken = default)
    {
        var query = _context.AuditLogs.AsQueryable();
        if (fromDate.HasValue)
            query = query.Where(x => EF.Property<DateTime>(x, "_timestamp") >= fromDate.Value);
        if (toDate.HasValue)
            query = query.Where(x => EF.Property<DateTime>(x, "_timestamp") <= toDate.Value);
        return await query.LongCountAsync(cancellationToken);
    }
}
