#if NET
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.Repository;
using Microsoft.EntityFrameworkCore;

namespace DigitalData.Core.Infrastructure
{
    /// <summary>
    /// Provides a generic implementation for CRUD (Create, Read, Update, Delete) operations within a given DbContext.
    /// </summary>
    /// <typeparam name="TEntity">The entity type for which the repository is created. Must be a class.</typeparam>
    /// <typeparam name="TId">The type of the entity's identifier.</typeparam>
    /// <typeparam name="TDbContext">The DbContext type associated with the entity.</typeparam>
    /// <remarks>
    /// This repository abstracts the common database operations, offering an asynchronous API to work with the entity's data.
    /// It leverages the EF Core's DbContext and DbSet to perform these operations.
    /// </remarks>
    [Obsolete("Use Repository")]
    public class CRUDRepository<TEntity, TId, TDbContext> : ICRUDRepository<TEntity, TId>
        where TEntity : class
        where TDbContext : DbContext
    {
        protected readonly TDbContext _dbContext;
        protected readonly DbSet<TEntity> _dbSet;

        /// <summary>
        /// Initializes a new instance of the CRUDRepository with the specified DbContext.
        /// </summary>
        /// <param name="dbContext">The DbContext instance to be used by the repository.</param>
        /// <param name="dbSet">The DbSet instance to be used by the repository.</param>
        public CRUDRepository(TDbContext dbContext, DbSet<TEntity> dbSet)
        {
            _dbContext = dbContext;
            _dbSet = dbSet;
        }

        /// <summary>
        /// Asynchronously creates a new entity in the database.
        /// </summary>
        /// <param name="entity">The entity to be added.</param>
        /// <returns>The created entity, or null if the entity cannot be added</returns>
        public virtual async Task<TEntity?> CreateAsync(TEntity entity)
        {
            await _dbSet.AddAsync(entity);
            await _dbContext.SaveChangesAsync();
            return entity;
        }

        /// <summary>
        /// Asynchronously retrieves an entity by its identifier.
        /// </summary>
        /// <param name="id">The identifier of the entity to find.</param>
        /// <returns>The entity found, or null if no entity is found with the specified identifier.</returns>
        public virtual async Task<TEntity?> ReadByIdAsync(TId id) => await _dbSet.FindAsync(id);

        /// <summary>
        /// Retrieves all entities of type <typeparamref name="TEntity"/> from the database.
        /// </summary>
        /// <remarks>
        /// This method returns an <see cref="IQueryable{TEntity}"/> of all entities in the database. 
        /// The result is not tracked by the context, which improves performance when you only need to read data without making modifications.
        /// </remarks>
        /// <returns>An <see cref="IQueryable{TEntity}"/> containing all entities of type <typeparamref name="TEntity"/>.</returns>
        protected virtual IQueryable<TEntity> ReadOnly() => _dbSet.AsNoTracking();

        /// <summary>
        /// Asynchronously retrieves all entities of type TEntity.
        /// </summary>
        /// <returns>An enumerable of all entities in the database.</returns>
        public virtual async Task<IEnumerable<TEntity>> ReadAllAsync() => await ReadOnly().ToListAsync();

        /// <summary>
        /// Asynchronously updates an existing entity in the repository.
        /// </summary>
        /// <param name="entity">The entity to be updated. This entity should already exist in the repository.</param>
        /// <returns>A task that represents the asynchronous operation. The task result contains a boolean value that indicates whether the update operation was successful. Returns true if one or more entities were successfully updated; otherwise, false.</returns>
        public virtual async Task<bool> UpdateAsync(TEntity entity)
        {
            _dbContext.Entry(entity).State = EntityState.Modified;
            var results = await _dbContext.SaveChangesAsync();
            return results > 0;
        }

        /// <summary>
        /// Asynchronously deletes an entity from the database.
        /// </summary>
        /// <param name="entity">The entity to be deleted.</param>
        /// <returns>If entity is deleted, return true othwerwise return false.</returns>
        public virtual async Task<bool> DeleteAsync(TEntity entity)
        {
            _dbSet.Remove(entity);
            var result = await _dbContext.SaveChangesAsync();
            return result > 0;
        }

        /// <summary>
        /// Asynchronously counts all entities in the repository.
        /// </summary>
        /// <returns>The total number of entities in the repository.</returns>
        public virtual async Task<int> CountAsync() => await _dbSet.CountAsync();

        /// <summary>
        /// Asynchronously counts the number of entities in the repository that match a specific identifier.
        /// </summary>
        /// <param name="id">The identifier of the entities to count.</param>
        /// <returns>The number of entities with the specified identifier.</returns>
        /// <remarks>
        /// This method provides a count of entities in the database that match the given identifier. 
        /// If there are multiple entities with the same identifier, they will all be counted. 
        /// The default implementation assumes that the identifier is unique for each entity.
        /// </remarks>
        public virtual async Task<int> CountAsync(TId id) => await _dbSet.Where(e => e.GetId().Equals(id)).CountAsync();
    }
}
#endif