using Back.Data.Contracts;
using Back.Data.Contracts;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using TaxPayer.Infrastructure.Persistence;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;

namespace Back.Data.Infrastructure.Repository
{
    public class RepositoryBase<T> : IAsyncRepository<T> where T : class
    {
        public readonly SqlDbContext _dbContext;
        private DbSet<T> _query;
        public RepositoryBase(SqlDbContext dbContext)
        {
            _dbContext = dbContext;
            _query = _dbContext.Set<T>();
        }
        public IQueryable<T> GetAll()
        {
            return _query.AsQueryable();
        }
        public IQueryable<T> Get(Expression<Func<T, bool>> predicate)
        {
            var query = _query.AsQueryable();
            query = query.AsNoTracking();
            return query.Where(predicate).AsQueryable();
        }
        public IQueryable<T> TrackingGet(Expression<Func<T, bool>> predicate)
        {
            var query = _query.AsQueryable();
            return query.Where(predicate).AsQueryable();
        }
        public IQueryable<T> Get(
            Expression<Func<T, bool>> predicate = null,
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
            string[] includeStrings = null,
            bool disableTracking = true)
        {
            var query = _query.AsQueryable();

            if (disableTracking) query = query.AsNoTracking();
            if (includeStrings != null)
            {
                foreach (var includeString in includeStrings)
                    if (!string.IsNullOrWhiteSpace(includeString)) query = query.Include(includeString);
            }


            if (predicate != null) query = query.Where(predicate);

            if (orderBy != null)
                return orderBy(query).AsQueryable();

            return query.AsQueryable();
        }

        public IQueryable<T> Get(
            Expression<Func<T, bool>> predicate = null,
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
            List<Expression<Func<T, object>>> includes = null,
            bool disableTracking = true)
        {
            var query = _query.AsQueryable();

            if (disableTracking) query = query.AsNoTracking();

            if (includes != null) query = includes.Aggregate(query, (current, include) => current.Include(include));

            if (predicate != null) query = query.Where(predicate);

            if (orderBy != null)
                return orderBy(query).AsQueryable();

            return query.AsQueryable();
        }

        public async Task<T> AddAsync(T entity)
        {
            try
            {
                await _query.AddAsync(entity);
                await _dbContext.SaveChangesAsync();
                return entity;
            }
            catch (Exception ex)
            {

                throw;
            }
       
        }
        public T? Add(T entity)
        {
            _query.Add(entity);
            var res = _dbContext.SaveChanges();
            return res > 0 ? entity : null;
            //await _dbContext.SaveChangesAsync();
            //return entity;
        }
        public async Task<bool> AddRangeAsync(ICollection<T> entites)
        {
            try
            {
                await _query.AddRangeAsync(entites);
                await _dbContext.SaveChangesAsync();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        public async Task<bool> UpdateAsync(T entity)
        {
            try
            {
           
                _dbContext.Entry(entity).State = EntityState.Modified;
                var result = await _dbContext.SaveChangesAsync();
                return result > 0;
            }
            catch (Exception)
            {
                return false;
                throw;
            }

        }
        public bool Update(T entity)
        {
            try
            {
                _dbContext.Update(entity);
                var result = _dbContext.SaveChanges();
                return result > 0;
            }
            catch (Exception)
            {
                return false;
            }

        }
        public async Task<T?> UpdateByObjAsync(T entity)
        {
            try
            {

                _dbContext.Entry(entity).State = EntityState.Modified;
     await _dbContext.SaveChangesAsync();
                return entity;
            }
            catch (Exception)
            {
                return null;
                throw;
            }

        }
        public T? UpdateByObj(T entity)
        {
            try
            {
                _dbContext.Update(entity);
                var result = _dbContext.SaveChanges();
                return entity;
            }
            catch (Exception)
            {
                return null;
            }

        }
        public async Task<bool> DeleteAsync(T entity)
        {
            try
            {
                _query.Remove(entity);
                var res = await _dbContext.SaveChangesAsync();
                return res > 0;
            }
            catch (Exception)
            {
                return false;
            }

        }
        public async Task<bool> DeleteRangeAsync(ICollection<T> entites)
        {
            try
            {
                _query.RemoveRange(entites);
                var res = await _dbContext.SaveChangesAsync();
                return res > 0;
            }
            catch (Exception)
            {
                return false;
            }

        }
        public async Task<List<SqlParameter>> RunSP(string query, List<SqlParameter> parameters)
        {
            await _dbContext.Database.ExecuteSqlRawAsync(query, parameters);
            return parameters;
        }
        public async Task ExecuteSql(string query)
        {
            await _dbContext.Database.ExecuteSqlRawAsync(query);
        }
        public bool Delete(T entity)
        {
            _query.Remove(entity);
            var res = _dbContext.SaveChanges();
            return res > 0;
        }
        public async Task<bool> AddBoolResultAsync(T entity)
        {
            int a = 0;
            await _query.AddAsync(entity);
            try
            {
                a = await _dbContext.SaveChangesAsync();
            }
            catch (Exception)
            {

                throw;
            }

            return a > 0;
        }
        public bool AddBoolResult(T entity)
        {
            _query.Add(entity);
            var res = _dbContext.SaveChanges();
            return res > 0;
        }
        public async Task<bool> UpdateRangeAsync(ICollection<T> entites)
        {
            try
            {
                //_dbContext.Entry(entites).State = EntityState.Modified;
                _dbContext.UpdateRange(entites);
                var result = await _dbContext.SaveChangesAsync();
                return result > 0;
            }
            catch (Exception)
            {
                return false;
                throw;
            }
        }
        public bool UpdateRange(ICollection<T> entites)
        {
            try
            {
                _dbContext.UpdateRange(entites);
                var result = _dbContext.SaveChanges();
                return result > 0;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}
//Sample Inclucde List
//new List<Expression<Func<AdmUsersPermission, object>>>
//              { x => x.System }