using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
namespace Core.Blueprint.DAL.SQLServer
{
    /// 
    /// The  class provides a comprehensive generic repository 
    /// for managing entities using Entity Framework Core with SQL Server as the underlying database.
    /// Designed as a package for consumption by external applications.
    /// 
    /// The entity type managed by the repository. Must be a class.
    /// The database context type. Must inherit from .
    public class EntityRepository : IEntityRepository
        where TEntity : class
        where TContext : DbContext
    {
        private readonly TContext _context;
        private readonly DbSet _dbSet;
        /// 
        /// Initializes a new instance of the  class with a specified database context.
        /// 
        /// The  for database operations.
        public EntityRepository(TContext context)
        {
            _context = context;
            _dbSet = _context.Set();
        }
        /// 
        /// Retrieves all entities of type  from the database.
        /// 
        /// A task representing the asynchronous operation, with a list of entities as the result.
        public async Task> GetAllAsync()
        {
            return await _dbSet.ToListAsync();
        }
        /// 
        /// Retrieves all entities of type  from the database that match a specified filter.
        /// 
        /// An expression to filter entities.
        /// A task representing the asynchronous operation, with a list of filtered entities as the result.
        public async Task> GetByConditionAsync(Expression> predicate)
        {
            return await _dbSet.Where(predicate).ToListAsync();
        }
        /// 
        /// Retrieves a single entity of type  by its identifier.
        /// 
        /// The identifier of the entity.
        /// A task representing the asynchronous operation, with the entity as the result, or null if not found.
        public async Task GetByIdAsync(int id)
        {
            var existingEntity = await _dbSet.FindAsync(id);
            if (existingEntity != null)
            {
                _context.Entry(existingEntity).State = EntityState.Detached;
            }
            return existingEntity;
        }
        /// 
        /// Adds a new entity to the database.
        /// 
        /// The entity to add.
        /// A task representing the asynchronous operation.
        public async Task AddAsync(TEntity entity)
        {
            await _dbSet.AddAsync(entity);
        }
        /// 
        /// Adds multiple entities to the database.
        /// 
        /// The collection of entities to add.
        /// A task representing the asynchronous operation.
        public async Task AddRangeAsync(IEnumerable entities)
        {
            await _dbSet.AddRangeAsync(entities);
        }
        /// 
        /// Updates an existing entity in the database.
        /// 
        /// The entity to update.
        /// The updated entity.
        public TEntity Update(TEntity entity)
        {
            _dbSet.Attach(entity);
            _context.Entry(entity).State = EntityState.Modified;
            return entity;
        }
        /// 
        /// Updates multiple entities in the database.
        /// 
        /// The collection of entities to update.
        public void UpdateRange(IEnumerable entities)
        {
            foreach (var entity in entities)
            {
                _dbSet.Attach(entity);
                _context.Entry(entity).State = EntityState.Modified;
            }
        }
        /// 
        /// Deletes an entity from the database.
        /// 
        /// The entity to delete.
        public void Delete(TEntity entity)
        {
            if (_context.Entry(entity).State == EntityState.Detached)
            {
                _dbSet.Attach(entity);
            }
            _dbSet.Remove(entity);
        }
        /// 
        /// Deletes multiple entities from the database.
        /// 
        /// The collection of entities to delete.
        public void DeleteRange(IEnumerable entities)
        {
            _dbSet.RemoveRange(entities);
        }
        /// 
        /// Retrieves the first entity matching the specified condition or null if no match is found.
        /// 
        /// An expression to filter entities.
        /// A task representing the asynchronous operation, with the matched entity as the result.
        public async Task FirstOrDefaultAsync(Expression> predicate)
        {
            return await _dbSet.FirstOrDefaultAsync(predicate);
        }
        /// 
        /// Determines if any entities exist that match the specified condition.
        /// 
        /// An expression to filter entities.
        /// A task representing the asynchronous operation, with a boolean result indicating existence.
        public async Task AnyAsync(Expression> predicate)
        {
            return await _dbSet.AnyAsync(predicate);
        }
        /// 
        /// Saves all pending changes to the database.
        /// 
        /// A task representing the asynchronous operation.
        public async Task SaveAsync()
        {
            await _context.SaveChangesAsync();
        }
        /// 
        /// Executes a raw SQL query and maps the result to the specified entity type.
        /// 
        /// The raw SQL query.
        /// Optional parameters for the query.
        /// An  representing the result set.
        public async Task> ExecuteRawSqlAsync(string sql, params object[] parameters)
        {
            return await _dbSet.FromSqlRaw(sql, parameters).ToListAsync();
        }
        /// 
        /// Counts the total number of entities in the database.
        /// 
        /// A task representing the asynchronous operation, with the count as the result.
        public async Task CountAsync()
        {
            return await _dbSet.CountAsync();
        }
    }
}