using LSFE.MobApp.Contracts;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using SQLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace LSFE.MobApp.Services
{
    public class Repository<T> : IRepository<T> where T : class, new()
    {
        private readonly SQLiteAsyncConnection _database;
        private readonly ILogger<Repository<T>> _logger;

        public Repository(SQLiteAsyncConnection database, ILogger<Repository<T>> logger)
        {
            _database = database;
            _logger = logger;
        }

        public async Task<List<T>> GetAllAsync()
        {
            try
            {
                return await _database.Table<T>().ToListAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting all {EntityType}", typeof(T).Name);
                throw;
            }
        }

        public async Task<T> GetByIdAsync(int id)
        {
            try
            {
                return await _database.Table<T>().Where(x => GetIdProperty(x).Equals(id)).FirstOrDefaultAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting {EntityType} by id {Id}", typeof(T).Name, id);
                throw;
            }
        }
        public async Task<List<T>> GetActiveAsync()
        {
            try
            {
                var isActiveProp = typeof(T).GetProperty("IsActive");
                if (isActiveProp != null && isActiveProp.PropertyType == typeof(bool))
                {
                    // Build expression: x => x.IsActive
                    var parameter = Expression.Parameter(typeof(T), "x");
                    var property = Expression.Property(parameter, isActiveProp);
                    var lambda = Expression.Lambda<Func<T, bool>>(property, parameter);

                    return await _database.Table<T>().Where(lambda).ToListAsync();
                }

                return await GetAllAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting active {EntityType}", typeof(T).Name);
                throw;
            }
        }

        public async Task<int> SaveAsync(T item)
        {
            try
            {
                return await _database.InsertAsync(item);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error saving {EntityType}", typeof(T).Name);
                throw;
            }
        }

        public async Task<int> UpdateAsync(T item)
        {
            try
            {
                return await _database.UpdateAsync(item);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating {EntityType}", typeof(T).Name);
                throw;
            }
        }

        public async Task<int> DeleteAsync(T item)
        {
            try
            {
                return await _database.DeleteAsync(item);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting {EntityType}", typeof(T).Name);
                throw;
            }
        }
        public async Task<int> TruncateAsync()
        {
            try
            {
                return await _database.DeleteAllAsync<T>();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error truncating table {EntityType}", typeof(T).Name);
                throw;
            }
        }
        public async Task<int> DeleteAsync(int id)
        {
            try
            {
                var item = await GetByIdAsync(id);
                if (item != null)
                {
                    return await DeleteAsync(item);
                }
                return 0;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting {EntityType} by id {Id}", typeof(T).Name, id);
                throw;
            }
        }

        public async Task<List<T>> QueryAsync(string query, params object[] args)
        {
            try
            {
                return await _database.QueryAsync<T>(query, args);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error executing query for {EntityType}", typeof(T).Name);
                throw;
            }
        }

        public async Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate)
        {
            try
            {
                return await _database.Table<T>().Where(predicate).FirstOrDefaultAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting first {EntityType}", typeof(T).Name);
                throw;
            }
        }

        public async Task<List<T>> WhereAsync(Expression<Func<T, bool>> predicate)
        {
            try
            {
                return await _database.Table<T>().Where(predicate).ToListAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error filtering {EntityType}", typeof(T).Name);
                throw;
            }
        }

        private object GetIdProperty(T item)
        {
            return typeof(T).GetProperty("Id")?.GetValue(item);
        }
    }
}