using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Strata.Code.DataAccess.Data;
using Strata.Code.DataAccess.Models;
using Strata.Code.DataAccess.Repositories.Interfaces;

namespace Strata.Code.DataAccess.Repositories
{
    public class BudgetConfigDefaultSettingRepository : IBudgetConfigDefaultSettingRepository
    {
        private readonly OnePlanDbContext _context;

        public BudgetConfigDefaultSettingRepository(OnePlanDbContext context)
        {
            _context = context ?? throw new ArgumentNullException(nameof(context));
        }

        public async Task<IEnumerable<BudgetConfigDefaultSetting>> GetAllAsync()
        {
            return await _context.Set<BudgetConfigDefaultSetting>()
                .OrderBy(x => x.SettingId)
                .ToListAsync();
        }

        public async Task<IEnumerable<BudgetConfigDefaultSetting>> GetAllWithChildrenAsync()
        {
            // Since the original Core20 code shows no direct children,
            // we keep this method for API consistency but it behaves same as GetAllAsync
            return await GetAllAsync();
        }

        public async Task<BudgetConfigDefaultSetting?> GetByIdAsync(int id)
        {
            return await _context.Set<BudgetConfigDefaultSetting>()
                .FirstOrDefaultAsync(x => x.SettingId == id);
        }

        public async Task<IEnumerable<BudgetConfigDefaultSetting>> GetByNameAsync(string name)
        {
            return await _context.Set<BudgetConfigDefaultSetting>()
                .Where(x => x.Name == name)
                .ToListAsync();
        }

        public async Task<IEnumerable<BudgetConfigDefaultSetting>> GetByIdsAsync(IEnumerable<int> ids)
        {
            return await _context.Set<BudgetConfigDefaultSetting>()
                .Where(x => ids.Contains(x.SettingId))
                .ToListAsync();
        }

        public async Task<BudgetConfigDefaultSetting> CreateAsync(BudgetConfigDefaultSetting setting)
        {
            setting.DateCreated = DateOnly.FromDateTime(DateTime.UtcNow);

            await _context.Set<BudgetConfigDefaultSetting>().AddAsync(setting);
            await _context.SaveChangesAsync();
            return setting;
        }

        public async Task<BudgetConfigDefaultSetting?> UpdateAsync(BudgetConfigDefaultSetting setting)
        {
            var existingSetting = await GetByIdAsync(setting.SettingId);
            if (existingSetting == null)
                return null;

            // Update properties
            existingSetting.Name = setting.Name;
            existingSetting.DefaultValue = setting.DefaultValue;
            existingSetting.Description = setting.Description;

            // EF Core tracks changes automatically
            await _context.SaveChangesAsync();
            return existingSetting;
        }

        public async Task<bool> DeleteAsync(int id)
        {
            var setting = await GetByIdAsync(id);
            if (setting == null)
                return false;

            _context.Remove(setting);
            await _context.SaveChangesAsync();
            return true;
        }

        public async Task<IEnumerable<BudgetConfigDefaultSetting>> FindByAsync(
            Expression<Func<BudgetConfigDefaultSetting, bool>> predicate)
        {
            return await _context.Set<BudgetConfigDefaultSetting>()
                .Where(predicate)
                .ToListAsync();
        }

        // Added validation method to match Core20's TryValidateSelf
        public bool ValidateSetting(BudgetConfigDefaultSetting setting, out IList<string> errors)
        {
            errors = new List<string>();

            if (string.IsNullOrWhiteSpace(setting.Name))
            {
                errors.Add("Name is required");
            }

            // Add any additional validation rules here

            return !errors.Any();
        }
    }
}
