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 Ladaer.BackEnd.Infrastructures.DTO.Models.Rewards;
using Microsoft.EntityFrameworkCore;

namespace Ladaer.BackEnd.Infrastructures.Services.Rewards
{
    public interface IRewardPenaltyService
    {
        
        Task<SmartTableResult<RewardPenaltyTicketItem>> Search(SmartTableParam param);


        /// <summary>
        /// Tạo phiếu thưởng/phạt thủ công
        /// </summary>
        Task<BaseResult> CreateManual(RewardPenaltyTicketModel model, CurrentUser currentUser);

        /// <summary>
        /// Duyệt phiếu
        /// </summary>
        Task<BaseResult> Approve(int id, CurrentUser currentUser);

        /// <summary>
        /// Từ chối phiếu
        /// </summary>
        Task<BaseResult> Reject(int id, CurrentUser currentUser);

        /// <summary>
        /// Gỡ/hủy phiếu (có giới hạn amnesty nếu là Auto)
        /// </summary>
        Task<BaseResult> Cancel(int id, string reason, CurrentUser currentUser);

        /// <summary>
        /// Lấy phiếu theo ID
        /// </summary>
        Task<RewardPenaltyTicketModel?> GetById(int id);
    }

    public class RewardPenaltyService : IRewardPenaltyService
    {
        private readonly IRepository<RewardPenaltyTicket> _ticketRepo;
        private readonly IRepository<UserCashViolation> _violationRepo;
        private readonly IRepository<AutoPenaltyConfig> _configRepo;

        public RewardPenaltyService(
            IRepository<RewardPenaltyTicket> ticketRepo,
            IRepository<UserCashViolation> violationRepo,
            IRepository<AutoPenaltyConfig> configRepo)
        {
            _ticketRepo = ticketRepo;
            _violationRepo = violationRepo;
            _configRepo = configRepo;
        }

        /// <summary>
        /// Tìm kiếm phiếu thưởng/phạt
        /// </summary>
        public async Task<SmartTableResult<RewardPenaltyTicketItem>> Search(SmartTableParam param)
        {
            IQueryable<RewardPenaltyTicket> query = _ticketRepo.Query().Include(x => x.User);

            // 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(x =>
                            x.Code.Contains(keyword));
                    }
                }
            }

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

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

        public async Task<BaseResult> CreateManual(RewardPenaltyTicketModel model, CurrentUser currentUser)
        {
            var result = new BaseResult();
            try
            {
                var ticket = new RewardPenaltyTicket
                {
                    Code = GenerateTicketCode(),
                    UserId = model.UserId,
                    TicketType = model.TicketType,
                    Source = TicketSource.Manual,
                    Amount = model.Amount,
                    Reason = model.Reason,
                    Status = TicketStatus.PendingApproval,
                    CreatedBy = currentUser.UserId,
                    CreatedByUserName = currentUser.UserName,
                    CreatedTime = DateTimeOffset.Now
                };

                await _ticketRepo.InsertAsync(ticket);
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }
            return result;
        }

        public async Task<BaseResult> Approve(int id, CurrentUser currentUser)
        {
            var result = new BaseResult();
            try
            {
                var ticket = await _ticketRepo.Query()
                    .FirstOrDefaultAsync(t => t.Id == id && !t.IsDeleted);

                if (ticket == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy phiếu";
                    return result;
                }

                if (ticket.Status != TicketStatus.PendingApproval)
                {
                    result.Result = Result.Failed;
                    result.Message = "Phiếu không ở trạng thái chờ duyệt";
                    return result;
                }

                ticket.Status = TicketStatus.Approved;
                ticket.UpdatedBy = currentUser.UserId;
                ticket.UpdatedByUserName = currentUser.UserName;
                ticket.UpdatedTime = DateTimeOffset.Now;

                await _ticketRepo.UpdateAsync(ticket);
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }
            return result;
        }

        public async Task<BaseResult> Reject(int id, CurrentUser currentUser)
        {
            var result = new BaseResult();
            try
            {
                var ticket = await _ticketRepo.Query()
                    .FirstOrDefaultAsync(t => t.Id == id && !t.IsDeleted);

                if (ticket == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy phiếu";
                    return result;
                }

                if (ticket.Status != TicketStatus.PendingApproval)
                {
                    result.Result = Result.Failed;
                    result.Message = "Phiếu không ở trạng thái chờ duyệt";
                    return result;
                }

                ticket.Status = TicketStatus.Rejected;
                ticket.UpdatedBy = currentUser.UserId;
                ticket.UpdatedByUserName = currentUser.UserName;
                ticket.UpdatedTime = DateTimeOffset.Now;

                await _ticketRepo.UpdateAsync(ticket);
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }
            return result;
        }

        public async Task<BaseResult> Cancel(int id, string reason, CurrentUser currentUser)
        {
            var result = new BaseResult();
            try
            {
                var ticket = await _ticketRepo.Query()
                    .FirstOrDefaultAsync(t => t.Id == id && !t.IsDeleted);

                if (ticket == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy phiếu";
                    return result;
                }

                if (ticket.Status != TicketStatus.PendingApproval && ticket.Status != TicketStatus.Approved)
                {
                    result.Result = Result.Failed;
                    result.Message = "Phiếu không ở trạng thái có thể hủy";
                    return result;
                }

                // Nếu là phiếu tự động, kiểm tra giới hạn amnesty
                if (ticket.Source == TicketSource.Automated)
                {
                    var config = await _configRepo.Query()
                        .Where(c => c.EffectiveTo == null)
                        .OrderByDescending(c => c.EffectiveFrom)
                        .FirstOrDefaultAsync();

                    if (config != null)
                    {
                        var cycleStart = GetCycleStart(config.ResetPolicy);
                        var amnestyUsed = await _ticketRepo.Query()
                            .CountAsync(t => t.UserId == ticket.UserId
                                && t.Source == TicketSource.Automated
                                && t.Status == TicketStatus.Canceled
                                && t.ForgivenAt != null
                                && t.ForgivenAt >= cycleStart);

                        if (amnestyUsed >= config.MaxAmnestyPerCycle)
                        {
                            result.Result = Result.Failed;
                            result.Message = $"User đã hết {config.MaxAmnestyPerCycle} lượt gỡ biên bản trong kỳ này";
                            return result;
                        }
                    }
                }

                ticket.Status = TicketStatus.Canceled;
                ticket.ForgivenBy = currentUser.UserId;
                ticket.ForgivenAt = DateTimeOffset.Now;
                ticket.ForgiveReason = reason;
                ticket.UpdatedBy = currentUser.UserId;
                ticket.UpdatedByUserName = currentUser.UserName;
                ticket.UpdatedTime = DateTimeOffset.Now;

                await _ticketRepo.UpdateAsync(ticket);

                // Cập nhật Violation thành Forgiven nếu có liên kết
                if (ticket.ViolationId.HasValue)
                {
                    var violation = await _violationRepo.Query()
                        .FirstOrDefaultAsync(v => v.Id == ticket.ViolationId.Value);
                    if (violation != null)
                    {
                        violation.Status = ViolationStatus.Forgiven;
                        await _violationRepo.UpdateAsync(violation);
                    }
                }
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }
            return result;
        }

        public async Task<RewardPenaltyTicketModel?> GetById(int id)
        {
            var ticket = await _ticketRepo.Query()
                .Include(x => x.User)
                .FirstOrDefaultAsync(t => t.Id == id && !t.IsDeleted);

            if (ticket == null) return null;

            return new RewardPenaltyTicketModel
            {
                Id = ticket.Id,
                Code = ticket.Code,
                UserId = ticket.UserId,
                FullName = ticket.User?.FullName ?? string.Empty,
                UserName = ticket.User?.UserName ?? string.Empty,
                TicketType = ticket.TicketType,
                Source = ticket.Source,
                Amount = ticket.Amount,
                Reason = ticket.Reason,
                Status = ticket.Status,
                ViolationId = ticket.ViolationId,
                BusinessDate = ticket.BusinessDate,
                ForgivenBy = ticket.ForgivenBy,
                ForgivenAt = ticket.ForgivenAt,
                ForgiveReason = ticket.ForgiveReason
            };
        }

        #region Helpers

        private static string GenerateTicketCode()
        {
            return $"RP-{DateTime.Now:yyyyMMdd}-{Guid.NewGuid().ToString("N")[..6].ToUpper()}";
        }

        private static DateTimeOffset GetCycleStart(ResetPolicy policy)
        {
            var now = DateTimeOffset.Now;
            return policy switch
            {
                ResetPolicy.Monthly => new DateTimeOffset(now.Year, now.Month, 1, 0, 0, 0, now.Offset),
                ResetPolicy.Quarterly => new DateTimeOffset(now.Year, ((now.Month - 1) / 3) * 3 + 1, 1, 0, 0, 0, now.Offset),
                ResetPolicy.Lifetime => DateTimeOffset.MinValue,
                _ => new DateTimeOffset(now.Year, now.Month, 1, 0, 0, 0, now.Offset)
            };
        }

        #endregion
    }

    #region Models



    #endregion
}
