using Lada.Framework.Data.Domains;
using Lada.Framework.Data.Domains.Premises;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.SmartTable;
using Lada.Framework.Infrastructures.Services;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Premises;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Premises;
using Ladaer.BackEnd.Infrastructures.DTO.Profiles;
using Microsoft.EntityFrameworkCore;

namespace Ladaer.BackEnd.Infrastructures.Services.Premises
{
    public interface IPremiseScoringService
    {
        Task<SmartTableResult<PremiseScoringCriteriaItem>> SearchCriteria(SmartTableParam param);
        Task<PremiseScoringCriteriaModel> GetCriteriaById(int id);
        Task<BaseResult> CreateOrUpdateCriteria(PremiseScoringCriteriaModel model);
        Task<BaseResult> DeleteCriteria(int id);
        Task<List<PremiseScoringCriteriaItem>> GetAllActiveCriteria();
    }

    public class PremiseScoringService : IPremiseScoringService
    {
        private readonly IRepository<PremiseScoringCriteria> _criteriaRepository;
        private readonly IRepository<PremiseScoringOption> _optionRepository;

        public PremiseScoringService(
            IRepository<PremiseScoringCriteria> criteriaRepository,
            IRepository<PremiseScoringOption> optionRepository)
        {
            _criteriaRepository = criteriaRepository;
            _optionRepository = optionRepository;
        }

        public async Task<SmartTableResult<PremiseScoringCriteriaItem>> SearchCriteria(SmartTableParam param)
        {
            var query = _criteriaRepository.Query()
                .Include(x => x.Options)
                .Where(x => !x.IsDeleted);

            if (param.Search?.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;
                if (search.Keyword != null)
                {
                    string keyword = ((string)search.Keyword).Trim();
                    if (!string.IsNullOrWhiteSpace(keyword))
                        query = query.Where(x => x.Name.Contains(keyword));
                }
            }

            // Sắp xếp mặc định theo thứ tự hiển thị
            param.Sort = new Sort() { Predicate = "DisplayOrder", Reverse = false };

            // Sử dụng AutoMapper extension
            return await query.ToSmartTableResultAsync(param, x => x.ToItem());
        }

        public async Task<PremiseScoringCriteriaModel> GetCriteriaById(int id)
        {
            var entity = await _criteriaRepository.Query()
                .Include(x => x.Options.Where(o => !o.IsDeleted))
                .FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted);

            if (entity == null) return null;

            var model = entity.ToModel();
            model.Options = entity.Options
                .OrderBy(o => o.DisplayOrder)
                .Select(o => o.ToModel())
                .ToList();

            return model;
        }

        public async Task<BaseResult> CreateOrUpdateCriteria(PremiseScoringCriteriaModel model)
        {
            BaseResult result = new BaseResult { Result = Result.Success };
            if (model.Id > 0)
            {
                var entity = await _criteriaRepository.GetByIdAsync(model.Id);
                if (entity != null)
                {
                    entity.Name = model.Name;
                    entity.Description = model.Description;
                    entity.CriteriaType = model.CriteriaType;
                    entity.DisplayOrder = model.DisplayOrder;
                    entity.IsActive = model.IsActive;
                    entity = entity.UpdateCommonInt(model.UpdatedBy, model.UpdatedByUserName);

                    var rs = await _criteriaRepository.UpdateAsync(entity);
                    if (rs > 0)
                    {
                        result.Result = Result.Success;

                        // Sync Options
                        await SyncOptions(entity.Id, model.Options, model.UpdatedBy, model.UpdatedByUserName);
                    }
                }
                else
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy tiêu chí";
                }
            }
            else
            {
                var entity = model.ToEntity();
                entity = entity.UpdateCommonInt(model.UpdatedBy, model.UpdatedByUserName);

                try
                {
                    var rs = await _criteriaRepository.InsertAsync(entity);
                    if (rs > 0)
                    {
                        result.Result = Result.Success;

                        // Sync Options
                        await SyncOptions(entity.Id, model.Options, model.UpdatedBy, model.UpdatedByUserName);
                    }
                }
                catch (Exception e)
                {
                    result.Result = Result.SystemError;
                    result.Message = e.Message;
                }
            }
            return result;
        }

        public async Task<BaseResult> DeleteCriteria(int id)
        {
            BaseResult result = new BaseResult { Result = Result.Success };
            if (id > 0)
            {
                var entity = await _criteriaRepository.GetByIdAsync(id);
                if (entity != null)
                {
                    var rs = await _criteriaRepository.DeleteAsync(entity);
                    if (rs > 0)
                    {
                        result.Result = Result.Success;
                    }
                }
                else
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy tiêu chí";
                }
            }
            else
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy tiêu chí";
            }
            return result;
        }

        public async Task<List<PremiseScoringCriteriaItem>> GetAllActiveCriteria()
        {
            var entities = await _criteriaRepository.Query()
                .Include(x => x.Options.Where(o=>!o.IsDeleted))
                .Where( x=> x.IsActive)
                .OrderBy(x => x.DisplayOrder)
                .ToListAsync();

            return entities.Select(x => x.ToItem()).ToList();
        }

        #region Private Helpers

        private async Task SyncOptions(int criteriaId, List<PremiseScoringOptionModel> options, int updatedBy, string updatedByUserName)
        {
            var existingOptions = await _optionRepository.Query()
                .Where(x => x.CriteriaId == criteriaId && !x.IsDeleted)
                .ToListAsync();

            // Soft delete removed options
            var updatedIds = options.Where(o => o.Id > 0).Select(o => o.Id).ToList();
            foreach (var existing in existingOptions.Where(e => !updatedIds.Contains(e.Id)))
            {
                existing.IsDeleted = true;
                existing.UpdateCommonInt(updatedBy, updatedByUserName);
                await _optionRepository.UpdateAsync(existing);
            }

            // Create or update
            foreach (var optionModel in options)
            {
                if (optionModel.Id > 0)
                {
                    var existing = existingOptions.FirstOrDefault(e => e.Id == optionModel.Id);
                    if (existing != null)
                    {
                        existing.Label = optionModel.Label;
                        existing.MinValue = optionModel.MinValue;
                        existing.MaxValue = optionModel.MaxValue;
                        existing.Score = optionModel.Score;
                        existing.DisplayOrder = optionModel.DisplayOrder;
                        existing.UpdateCommonInt(updatedBy, updatedByUserName);
                        await _optionRepository.UpdateAsync(existing);
                    }
                }
                else
                {
                    var newOption = new PremiseScoringOption
                    {
                        CriteriaId = criteriaId,
                        Label = optionModel.Label,
                        MinValue = optionModel.MinValue,
                        MaxValue = optionModel.MaxValue,
                        Score = optionModel.Score,
                        DisplayOrder = optionModel.DisplayOrder
                    };
                    newOption.UpdateCommonInt(updatedBy, updatedByUserName);
                    await _optionRepository.InsertAsync(newOption);
                }
            }
        }

        #endregion
    }
}
