using Lada.Framework.Data.Domains.Rewards;
using Lada.Framework.Data.Enums;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.SmartTable;
using Lada.Framework.Infrastructures;
using Ladaer.BackEnd.Infrastructures.DTO.Profiles;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Rewards;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;

namespace Ladaer.BackEnd.Infrastructures.Services.Rewards
{
    public interface IAutoPenaltyConfigService
    {
        /// <summary>
        /// Lấy cấu hình đang hiệu lực
        /// </summary>
        Task<AutoPenaltyConfigModel?> GetCurrentConfig();

        /// <summary>
        /// Cập nhật cấu hình (tạo version mới)
        /// </summary>
        Task<BaseResult> UpdateConfig(AutoPenaltyConfigModel model, CurrentUser currentUser);

        /// <summary>
        /// Tạm dừng / Mở lại
        /// </summary>
        Task<BaseResult> TogglePause(bool isPaused, string? pauseReason, CurrentUser currentUser);

        /// <summary>
        /// Tìm kiếm danh sách cấu hình
        /// </summary>
        Task<SmartTableResult<AutoPenaltyConfigItem>> Search(SmartTableParam param);

        /// <summary>
        /// Lấy chi tiết cấu hình theo ID
        /// </summary>
        Task<AutoPenaltyConfigModel?> GetById(int id);

        /// <summary>
        /// Tạo mới hoặc cập nhật cấu hình
        /// </summary>
        Task<BaseResult> CreateOrUpdate(AutoPenaltyConfigModel model, CurrentUser currentUser);

        /// <summary>
        /// Xóa cấu hình
        /// </summary>
        Task<BaseResult> Delete(int id, CurrentUser currentUser);
    }

    public class AutoPenaltyConfigService : IAutoPenaltyConfigService
    {
        private readonly IRepository<AutoPenaltyConfig> _configRepo;
        private readonly IRepository<AutoPenaltyLevel> _levelRepo;
        private readonly IRepository<ConfigAuditLog> _auditRepo;

        public AutoPenaltyConfigService(
            IRepository<AutoPenaltyConfig> configRepo,
            IRepository<AutoPenaltyLevel> levelRepo,
            IRepository<ConfigAuditLog> auditRepo)
        {
            _configRepo = configRepo;
            _levelRepo = levelRepo;
            _auditRepo = auditRepo;
        }

        public async Task<AutoPenaltyConfigModel?> GetCurrentConfig()
        {
            var config = await _configRepo.Query()
                .Include(c => c.Levels)
                .Where(c => c.EffectiveTo == null)
                .OrderByDescending(c => c.EffectiveFrom)
                .FirstOrDefaultAsync();

            if (config == null) return null;

            return MapToModel(config);
        }

        public async Task<BaseResult> UpdateConfig(AutoPenaltyConfigModel model, CurrentUser currentUser)
        {
            var result = new BaseResult();
            try
            {
                // Lấy cấu hình hiện tại để audit
                var oldConfig = await _configRepo.Query()
                    .Include(c => c.Levels)
                    .Where(c => c.EffectiveTo == null)
                    .OrderByDescending(c => c.EffectiveFrom)
                    .FirstOrDefaultAsync();

                string? oldValue = oldConfig != null ? JsonSerializer.Serialize(MapToModel(oldConfig)) : null;

                // Đóng cấu hình cũ
                if (oldConfig != null)
                {
                    oldConfig.EffectiveTo = DateTimeOffset.Now;
                    oldConfig.UpdatedBy = currentUser.UserId;
                    oldConfig.UpdatedByUserName = currentUser.UserName;
                    oldConfig.UpdatedTime = DateTimeOffset.Now;
                    await _configRepo.UpdateAsync(oldConfig);
                }

                // Tạo cấu hình mới (versioning)
                var newConfig = new AutoPenaltyConfig
                {
                    IsEnabled = model.IsEnabled,
                    IsPaused = model.IsPaused,
                    PauseReason = model.PauseReason,
                    CutoffTimeNextDay = model.CutoffTimeNextDay,
                    ResetPolicy = model.ResetPolicy,
                    MaxAmnestyPerCycle = model.MaxAmnestyPerCycle,
                    EffectiveFrom = DateTimeOffset.Now,
                    EffectiveTo = null,
                    CreatedBy = currentUser.UserId,
                    CreatedByUserName = currentUser.UserName,
                    CreatedTime = DateTimeOffset.Now
                };

                await _configRepo.InsertAsync(newConfig);

                // Tạo Levels cho config mới
                if (model.Levels != null && model.Levels.Any())
                {
                    foreach (var levelModel in model.Levels)
                    {
                        var level = new AutoPenaltyLevel
                        {
                            ConfigId = newConfig.Id,
                            FromCount = levelModel.FromCount,
                            ToCount = levelModel.ToCount,
                            ActionType = levelModel.ActionType,
                            PenaltyAmount = levelModel.PenaltyAmount,
                            CreatedBy = currentUser.UserId,
                            CreatedByUserName = currentUser.UserName,
                            CreatedTime = DateTimeOffset.Now
                        };
                        await _levelRepo.InsertAsync(level);
                    }
                }

                // Ghi audit log
                var auditLog = new ConfigAuditLog
                {
                    ConfigType = "AutoPenaltyConfig",
                    OldValue = oldValue,
                    NewValue = JsonSerializer.Serialize(model),
                    ChangedBy = currentUser.UserId,
                    ChangedAt = DateTimeOffset.Now,
                    Reason = model.ChangeReason,
                    CreatedBy = currentUser.UserId,
                    CreatedByUserName = currentUser.UserName,
                    CreatedTime = DateTimeOffset.Now
                };
                await _auditRepo.InsertAsync(auditLog);
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }
            return result;
        }

        public async Task<BaseResult> TogglePause(bool isPaused, string? pauseReason, CurrentUser currentUser)
        {
            var result = new BaseResult();
            try
            {
                var config = await _configRepo.Query()
                    .Where(c => c.EffectiveTo == null)
                    .OrderByDescending(c => c.EffectiveFrom)
                    .FirstOrDefaultAsync();

                if (config == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Chưa có cấu hình nào";
                    return result;
                }

                config.IsPaused = isPaused;
                config.PauseReason = isPaused ? pauseReason : null;
                config.UpdatedBy = currentUser.UserId;
                config.UpdatedByUserName = currentUser.UserName;
                config.UpdatedTime = DateTimeOffset.Now;

                await _configRepo.UpdateAsync(config);

                // Audit log
                var auditLog = new ConfigAuditLog
                {
                    ConfigType = "PauseToggle",
                    OldValue = (!isPaused).ToString(),
                    NewValue = isPaused.ToString(),
                    ChangedBy = currentUser.UserId,
                    ChangedAt = DateTimeOffset.Now,
                    Reason = pauseReason,
                    CreatedBy = currentUser.UserId,
                    CreatedByUserName = currentUser.UserName,
                    CreatedTime = DateTimeOffset.Now
                };
                await _auditRepo.InsertAsync(auditLog);
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// Tìm kiếm danh sách cấu hình
        /// </summary>
        public async Task<SmartTableResult<AutoPenaltyConfigItem>> Search(SmartTableParam param)
        {
            IQueryable<AutoPenaltyConfig> query = _configRepo.Query().Include(c => c.Levels);

            // Filter by search
            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(c =>
                            (c.PauseReason != null && c.PauseReason.Contains(keyword)) ||
                            (c.CreatedByUserName != null && c.CreatedByUserName.Contains(keyword)));
                    }
                }
            }

            // Sắp xếp mặc định
            param.Sort = new Sort() { Predicate = "CreatedTime", Reverse = true };

            return await query.ToSmartTableResultAsync(param, x => x.ToItem());
        }

        /// <summary>
        /// Lấy chi tiết cấu hình theo ID
        /// </summary>
        public async Task<AutoPenaltyConfigModel?> GetById(int id)
        {
            var config = await _configRepo.Query()
                .Include(c => c.Levels)
                .FirstOrDefaultAsync(c => c.Id == id && !c.IsDeleted);

            if (config == null) return null;

            return MapToModel(config);
        }

        /// <summary>
        /// Tạo mới hoặc cập nhật cấu hình
        /// </summary>
        public async Task<BaseResult> CreateOrUpdate(AutoPenaltyConfigModel model, CurrentUser currentUser)
        {
            var result = new BaseResult();
            try
            {
                if (model.Id == 0)
                {
                    // Tạo mới
                    var newConfig = new AutoPenaltyConfig
                    {
                        IsEnabled = model.IsEnabled,
                        IsPaused = model.IsPaused,
                        PauseReason = model.PauseReason,
                        CutoffTimeNextDay = model.CutoffTimeNextDay,
                        ResetPolicy = model.ResetPolicy,
                        MaxAmnestyPerCycle = model.MaxAmnestyPerCycle,
                        EffectiveFrom = DateTimeOffset.Now,
                        EffectiveTo = null,
                        CreatedBy = currentUser.UserId,
                        CreatedByUserName = currentUser.UserName,
                        CreatedTime = DateTimeOffset.Now
                    };

                    await _configRepo.InsertAsync(newConfig);

                    // Tạo Levels
                    if (model.Levels != null && model.Levels.Any())
                    {
                        foreach (var levelModel in model.Levels)
                        {
                            var level = new AutoPenaltyLevel
                            {
                                ConfigId = newConfig.Id,
                                FromCount = levelModel.FromCount,
                                ToCount = levelModel.ToCount,
                                ActionType = levelModel.ActionType,
                                PenaltyAmount = levelModel.PenaltyAmount,
                                CreatedBy = currentUser.UserId,
                                CreatedByUserName = currentUser.UserName,
                                CreatedTime = DateTimeOffset.Now
                            };
                            await _levelRepo.InsertAsync(level);
                        }
                    }

                    // Audit log
                    var auditLog = new ConfigAuditLog
                    {
                        ConfigType = "AutoPenaltyConfig",
                        OldValue = null,
                        NewValue = JsonSerializer.Serialize(model),
                        ChangedBy = currentUser.UserId,
                        ChangedAt = DateTimeOffset.Now,
                        Reason = model.ChangeReason ?? "Tạo mới cấu hình",
                        CreatedBy = currentUser.UserId,
                        CreatedByUserName = currentUser.UserName,
                        CreatedTime = DateTimeOffset.Now
                    };
                    await _auditRepo.InsertAsync(auditLog);
                }
                else
                {
                    // Cập nhật
                    var existingConfig = await _configRepo.Query()
                        .Include(c => c.Levels)
                        .FirstOrDefaultAsync(c => c.Id == model.Id && !c.IsDeleted);

                    if (existingConfig == null)
                    {
                        result.Result = Result.Failed;
                        result.Message = "Không tìm thấy cấu hình";
                        return result;
                    }

                    string oldValue = JsonSerializer.Serialize(MapToModel(existingConfig));

                    // Cập nhật thông tin cấu hình
                    existingConfig.IsEnabled = model.IsEnabled;
                    existingConfig.IsPaused = model.IsPaused;
                    existingConfig.PauseReason = model.PauseReason;
                    existingConfig.CutoffTimeNextDay = model.CutoffTimeNextDay;
                    existingConfig.ResetPolicy = model.ResetPolicy;
                    existingConfig.MaxAmnestyPerCycle = model.MaxAmnestyPerCycle;
                    existingConfig.UpdatedBy = currentUser.UserId;
                    existingConfig.UpdatedByUserName = currentUser.UserName;
                    existingConfig.UpdatedTime = DateTimeOffset.Now;

                    await _configRepo.UpdateAsync(existingConfig);

                    // Xóa levels cũ và tạo levels mới
                    if (existingConfig.Levels != null)
                    {
                        foreach (var oldLevel in existingConfig.Levels.ToList())
                        {
                            await _levelRepo.DeleteAsync(oldLevel);
                        }
                    }

                    if (model.Levels != null && model.Levels.Any())
                    {
                        foreach (var levelModel in model.Levels)
                        {
                            var level = new AutoPenaltyLevel
                            {
                                ConfigId = existingConfig.Id,
                                FromCount = levelModel.FromCount,
                                ToCount = levelModel.ToCount,
                                ActionType = levelModel.ActionType,
                                PenaltyAmount = levelModel.PenaltyAmount,
                                CreatedBy = currentUser.UserId,
                                CreatedByUserName = currentUser.UserName,
                                CreatedTime = DateTimeOffset.Now
                            };
                            await _levelRepo.InsertAsync(level);
                        }
                    }

                    // Audit log
                    var auditLog = new ConfigAuditLog
                    {
                        ConfigType = "AutoPenaltyConfig",
                        OldValue = oldValue,
                        NewValue = JsonSerializer.Serialize(model),
                        ChangedBy = currentUser.UserId,
                        ChangedAt = DateTimeOffset.Now,
                        Reason = model.ChangeReason ?? "Cập nhật cấu hình",
                        CreatedBy = currentUser.UserId,
                        CreatedByUserName = currentUser.UserName,
                        CreatedTime = DateTimeOffset.Now
                    };
                    await _auditRepo.InsertAsync(auditLog);
                }
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// Xóa cấu hình (soft delete)
        /// </summary>
        public async Task<BaseResult> Delete(int id, CurrentUser currentUser)
        {
            var result = new BaseResult();
            try
            {
                var config = await _configRepo.Query()
                    .FirstOrDefaultAsync(c => c.Id == id && !c.IsDeleted);

                if (config == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy cấu hình";
                    return result;
                }

                config.IsDeleted = true;
                config.UpdatedBy = currentUser.UserId;
                config.UpdatedByUserName = currentUser.UserName;
                config.UpdatedTime = DateTimeOffset.Now;

                await _configRepo.UpdateAsync(config);

                // Audit log
                var auditLog = new ConfigAuditLog
                {
                    ConfigType = "AutoPenaltyConfig",
                    OldValue = JsonSerializer.Serialize(new { Id = id }),
                    NewValue = null,
                    ChangedBy = currentUser.UserId,
                    ChangedAt = DateTimeOffset.Now,
                    Reason = "Xóa cấu hình",
                    CreatedBy = currentUser.UserId,
                    CreatedByUserName = currentUser.UserName,
                    CreatedTime = DateTimeOffset.Now
                };
                await _auditRepo.InsertAsync(auditLog);
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }
            return result;
        }

        private static AutoPenaltyConfigModel MapToModel(AutoPenaltyConfig config)
        {
            return new AutoPenaltyConfigModel
            {
                Id = config.Id,
                IsEnabled = config.IsEnabled,
                IsPaused = config.IsPaused,
                PauseReason = config.PauseReason,
                CutoffTimeNextDay = config.CutoffTimeNextDay,
                ResetPolicy = config.ResetPolicy,
                MaxAmnestyPerCycle = config.MaxAmnestyPerCycle,
                Levels = config.Levels?.Select(l => new AutoPenaltyLevelModel
                {
                    Id = l.Id,
                    FromCount = l.FromCount,
                    ToCount = l.ToCount,
                    ActionType = l.ActionType,
                    PenaltyAmount = l.PenaltyAmount
                }).ToList() ?? new List<AutoPenaltyLevelModel>()
            };
        }
    }

    #region Models

    public class AutoPenaltyConfigModel
    {
        public int Id { get; set; }
        public bool IsEnabled { get; set; }
        public bool IsPaused { get; set; }
        public string? PauseReason { get; set; }
        public TimeSpan CutoffTimeNextDay { get; set; }
        public ResetPolicy ResetPolicy { get; set; }
        public int MaxAmnestyPerCycle { get; set; }
        public string? ChangeReason { get; set; }
        public List<AutoPenaltyLevelModel> Levels { get; set; } = new();
    }

    public class AutoPenaltyLevelModel
    {
        public int Id { get; set; }
        public int FromCount { get; set; }
        public int? ToCount { get; set; }
        public PenaltyActionType ActionType { get; set; }
        public decimal PenaltyAmount { get; set; }
    }

    #endregion
}
