using Marten;
using Netina.Repository.Abstracts;

namespace Netina.Infrastructure.Marten;

public class MartenRepository<TMartenEntity>(IDocumentStore documentStore, ICurrentUserService currentUserService)
    : IMartenRepository<TMartenEntity>
    where TMartenEntity : IMartenEntity
{
    private readonly ICurrentUserService _currentUserService = currentUserService;

    public async Task<List<TMartenEntity>> GetEntitiesAsync(CancellationToken cancellation)
    {
        await using var session = documentStore.QuerySession();
        var entities = await session
            .Query<TMartenEntity>()
            .ToListAsync(cancellation);
        return entities.ToList();
    }
    public async Task<List<TMartenEntity>> GetEntitiesAsync(int page, int count, CancellationToken cancellation)
    {
        await using var session = documentStore.QuerySession();
        var entities = await session
            .Query<TMartenEntity>()
            .Skip(page * count)
            .Take(count)
            .ToListAsync(cancellation);
        return entities.ToList();
    }

    public async Task<List<TMartenEntity>> GetEntitiesAsync(Expression<Func<TMartenEntity, bool>> expression, int page, int count, CancellationToken cancellation)
    {
        await using var session = documentStore.QuerySession();
        var entities = await session.Query<TMartenEntity>().Where(expression)
            .Skip(page * count)
            .Take(count)
            .ToListAsync(cancellation);
        return entities.ToList();
    }
    public async Task<List<TMartenEntity>> GetEntitiesAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation)
    {
        await using var session = documentStore.QuerySession();
        var entities = await session.Query<TMartenEntity>().Where(expression).ToListAsync(cancellation);
        return entities.ToList();
    }

    public async Task<TMartenEntity> GetEntityAsync(Guid id, CancellationToken cancellation)
    {
        await using var session = documentStore.QuerySession();
        var setting = await session.LoadAsync<TMartenEntity>(id, cancellation);
        if (setting == null)
            throw new AppException($"{nameof(setting)} not found", ApiResultStatusCode.NotFound);
        return setting;
    }

    public async Task<TMartenEntity?> GetEntityAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation)
    {
        await using var session = documentStore.QuerySession();
        var entity = await session.Query<TMartenEntity>().FirstOrDefaultAsync(expression, cancellation);
        return entity;
    }

    public async Task AddOrUpdateEntityAsync(TMartenEntity entity, CancellationToken cancellation)
    {
        if (entity == null)
            throw new AppException($"{nameof(entity)} is null", ApiResultStatusCode.BadRequest);

        await using var session = documentStore.LightweightSession();
        session.Store(entity);
        await session.SaveChangesAsync(cancellation);
    }

    public async Task UpdateEntityAsync(TMartenEntity entity, CancellationToken cancellation = default)
    {
        if (entity == null)
            throw new AppException($"{nameof(entity)} is null", ApiResultStatusCode.BadRequest);

        await using var session = documentStore.LightweightSession();
        session.Update(entity);
        await session.SaveChangesAsync(cancellation);
    }

    public async Task RemoveEntityAsync(TMartenEntity entity, CancellationToken cancellation)
    {
        if (entity == null)
            throw new AppException($"{nameof(entity)} is null", ApiResultStatusCode.BadRequest);
        await using var session = documentStore.LightweightSession();
        session.Delete(entity);
        await session.SaveChangesAsync(cancellation);
    }
}