using IWS5.DatabaseAccess.Interfaces;
using IWS5.DatabaseAccess.IwsDataContext;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;

namespace IWS5.DatabaseAccess.Repositories;

public class IWSRepository<T> : IIWSRepository<T> where T : class
{
    private readonly GreenfieldPd2015Context _context;
    private readonly DbSet<T> _dbSet;

    protected IWSRepository(GreenfieldPd2015Context context)
    {
        _context = context;
        _dbSet = context.Set<T>();
    }
    
    public async Task<bool> AnyAsync(Expression<Func<T, bool>> predicate)
    {
        return await _dbSet.AsNoTracking().AnyAsync(predicate);
    }

    public async Task<List<T>> ListAsync(Expression<Func<T, bool>>? predicate = null, params Expression<Func<T, object>>[] includes)
    {
        var query = _dbSet.AsNoTracking();
        if (includes.Any())
        {
            query = includes.Aggregate(query, (current, include) => current.Include(include));
        }
        if (predicate != null)
        {
            query = query.Where(predicate);
        }
        
        var value = await query.ToListAsync();
        return value;
    }

    public async Task<T> FindAsync(Expression<Func<T, bool>>? predicate = null, params Expression<Func<T, object>>[] includes)
    {
        var query = _dbSet.AsNoTracking();

        if (includes.Any())
        {
            query = includes.Aggregate(query, (current, include) => current.Include(include));
        }

        if (predicate != null)
        {
            return await query.FirstOrDefaultAsync(predicate);
        }

        return await query.FirstOrDefaultAsync();
    }

    public async Task AddAsync(T entity)
    {
        await _dbSet.AddAsync(entity);
    }

    public virtual async Task AddRangeAsync(IEnumerable<T> entities)
    {
        await _dbSet.AddRangeAsync(entities);
    }

    public async Task RemoveAsync(T entity)
    {
        _dbSet.Remove(entity);
        await Task.CompletedTask;
    }

    public async Task RemoveRangeAsync(IEnumerable<T> entities)
    {
        _dbSet.RemoveRange(entities);
        await Task.CompletedTask;
    }

    public async Task UpdateAsync(T entity)
    {
        _context.Update(entity);
        await _context.SaveChangesAsync();
    }

    public async Task SaveChangesAsync()
    {
        await _context.SaveChangesAsync();
    }

    public void UpdateRangeAsync(IEnumerable<T> entities)
    {
        _context.UpdateRange(entities);
    }
}
