using LSFE.Domain.Contracts.Maintenance;
using LSFE.Infrastructure.Database;
using LSFE.Infrastructure.Dto.Maintenance;
using LSFE.Infrastructure.Model;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace LSFE.Domain.Services.Maintenance
{
    public class MaintenanceRepo<TEntity> : IMaintenanceRepo<TEntity> where TEntity : class
    {
        private readonly LSFEDbContext _context;
        private readonly DbSet<TEntity> _dbSet;
        public MaintenanceRepo(LSFEDbContext context)
        {
            _context = context;
            _dbSet = _context.Set<TEntity>();
        }
        public async Task<bool> AnyAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await _dbSet.AnyAsync(predicate);
        }
        public IQueryable<TEntity> Query()
        {
            return _context.Set<TEntity>().AsQueryable(); 
        }
        public async Task<List<TEntity>> GetAllAsync(params Expression<Func<TEntity, object>>[] includeProperties)
        {
            IQueryable<TEntity> query = _context.Set<TEntity>();

            if (includeProperties != null)
            {
                foreach (var includeProperty in includeProperties)
                {
                    query = query.Include(includeProperty);
                }
            }

            return await query.ToListAsync();
        }

        public async Task<Response> AddOrUpdateAsync(TEntity entity)
        {
            try
            {
                var keyProperty = _context.Model.FindEntityType(typeof(TEntity))?
                    .FindPrimaryKey()?.Properties.First();

                if (keyProperty == null)
                    throw new InvalidOperationException($"No key defined for {typeof(TEntity).Name}");

                var keyValue = keyProperty.PropertyInfo?.GetValue(entity);

                var existing = await _context.Set<TEntity>().FindAsync(keyValue);

                if (existing == null)
                {
                    await _context.Set<TEntity>().AddAsync(entity);
                }
                else
                {
                    _context.Entry(existing).CurrentValues.SetValues(entity);
                    _context.Entry(existing).State = EntityState.Modified;
                }

                return new Response { Success = true, MessCode = 1 };
            }
            catch (Exception ex)
            {
                return new Response
                {
                    Success = false,
                    Message = ex.ToString(),
                    MessCode = 0
                };
            }
        }

        public async Task<Response> SoftDeleteAsync(int id)
        {
            var entity = await _context.Set<TEntity>().FindAsync(id);
            if (entity == null)
                return new Response { Success = false, Message = "Not found" };

            var prop = typeof(TEntity).GetProperty("IsActive");
            if (prop != null)
                prop.SetValue(entity, false);

            return new Response { Success = true };
        }
        public async Task<TEntity?> FindAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await _context.Set<TEntity>().FirstOrDefaultAsync(predicate);
        }

        public async Task<TEntity?> GetByIdAsync(object id)
        {
            return await _context.Set<TEntity>().FindAsync(id);
        }

        public async Task<IEnumerable<TEntity>> FindAllAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await _context.Set<TEntity>()
                .Where(predicate)
                .AsNoTracking() 
                .ToListAsync();
        }
        public async Task AddRangeAsync(IEnumerable<TEntity> entities)
        {
            if (entities == null || !entities.Any())
            {
                return;
            }

            await _context.Set<TEntity>().AddRangeAsync(entities);
        }
        public async Task<Response> DeleteAsync(Guid id)
        {
            var entity = await _context.Set<TEntity>().FindAsync(id);

            if (entity == null)
                return new Response { Success = false, Message = "Not found" };

            _context.Set<TEntity>().Remove(entity); 
            await _context.SaveChangesAsync();    

            return new Response { Success = true };
        }
    }
}
