using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Application.Common.Models;
using Microsoft.EntityFrameworkCore;

namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange;

public class GetOrdersByDateRangeQueryHandler : IRequestHandler<GetOrdersByDateRangeQuery, GetOrdersByDateRangeResponseDto>
{
    private readonly IApplicationDbContext _context;
    private readonly ILogger<GetOrdersByDateRangeQueryHandler> _logger;

    public GetOrdersByDateRangeQueryHandler(
        IApplicationDbContext context,
        ILogger<GetOrdersByDateRangeQueryHandler> logger)
    {
        _context = context;
        _logger = logger;
    }

    public async Task<GetOrdersByDateRangeResponseDto> Handle(GetOrdersByDateRangeQuery request, CancellationToken cancellationToken)
    {
        var query = _context.UserOrders
            .AsNoTracking()
            .Include(o => o.User)
            .Include(o => o.FactorDetails)
            .AsQueryable();

        query = query.Where(o => o.Created >= request.StartDate && o.Created <= request.EndDate);

        if (request.Status.HasValue)
        {
            query = query.Where(o => o.DeliveryStatus == request.Status.Value);
        }

        if (request.UserId.HasValue)
        {
            query = query.Where(o => o.UserId == request.UserId.Value);
        }

        var totalCount = await query.CountAsync(cancellationToken);

        var response = new GetOrdersByDateRangeResponseDto
        {
            MetaData = new MetaData
            {
                CurrentPage = request.PageIndex,
                TotalPage = totalCount == 0 ? 0 : (int)Math.Ceiling(totalCount / (double)request.PageSize),
                PageSize = request.PageSize,
                TotalCount = totalCount,
                HasNext = totalCount > 0 && request.PageIndex * request.PageSize < totalCount,
                HasPrevious = request.PageIndex > 1
            }
        };

        if (totalCount == 0)
        {
            return response;
        }

        var orders = await query
            .OrderByDescending(o => o.Created)
            .Skip((request.PageIndex - 1) * request.PageSize)
            .Take(request.PageSize)
            .ToListAsync(cancellationToken);

        response.Orders = orders.Select(o =>
        {
            var firstName = o.User?.FirstName ?? string.Empty;
            var lastName = o.User?.LastName ?? string.Empty;
            var fullName = $"{firstName} {lastName}".Trim();

            return new OrderSummaryDto
            {
                Id = o.Id,
                UserId = o.UserId,
                UserFullName = fullName,
                Amount = o.Amount,
                // در حال حاضر فیلد DiscountedPrice در UserOrder وجود ندارد، پس همان Amount برگردانده می‌شود
                DiscountedPrice = o.Amount,
                Status = o.DeliveryStatus,
                Created = o.Created,
                ShippedAt = null,
                DeliveredAt = null,
                ItemsCount = o.FactorDetails?.Count ?? 0
            };
        }).ToList();

        _logger.LogInformation(
            "Retrieved {Count} orders for date range {Start} to {End}",
            response.Orders.Count,
            request.StartDate,
            request.EndDate);

        return response;
    }
}
