using MediatR;
using TakeoutSaaS.Application.App.Orders.Dto;
using TakeoutSaaS.Application.App.Orders.Queries;
using TakeoutSaaS.Domain.Orders.Entities;
using TakeoutSaaS.Domain.Orders.Enums;
using TakeoutSaaS.Domain.Orders.Repositories;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Orders.Handlers;

/// <summary>
/// 全部订单列表查询处理器。
/// </summary>
public sealed class SearchOrderAllListQueryHandler(
    IOrderRepository orderRepository,
    ITenantProvider tenantProvider)
    : IRequestHandler<SearchOrderAllListQuery, PagedResult<OrderAllListItemDto>>
{
    /// <inheritdoc />
    public async Task<PagedResult<OrderAllListItemDto>> Handle(SearchOrderAllListQuery request, CancellationToken cancellationToken)
    {
        var tenantId = tenantProvider.GetCurrentTenantId();
        var page = Math.Max(1, request.Page);
        var pageSize = Math.Clamp(request.PageSize, 1, 200);

        var (pagedOrders, totalCount) = await orderRepository.SearchAllOrdersPageAsync(
            tenantId,
            request.StoreId,
            request.StartAt,
            request.EndAt,
            request.Status,
            request.RefundedOnly,
            request.DeliveryType,
            request.PaymentMethod,
            request.Keyword,
            request.SortBy,
            request.SortDescending,
            page,
            pageSize,
            cancellationToken);

        var refundedSet = await LoadRefundedOrderIdsAsync(
            pagedOrders.Select(order => order.Id).ToList(),
            tenantId,
            cancellationToken);

        var itemsLookup = await orderRepository.GetItemsByOrderIdsAsync(
            pagedOrders.Select(order => order.Id).ToList(),
            tenantId,
            cancellationToken);

        var rows = pagedOrders
            .Select(order =>
            {
                var isRefunded = refundedSet.Contains(order.Id);
                return new OrderAllListItemDto
                {
                    OrderId = order.Id,
                    OrderNo = order.OrderNo,
                    OrderedAt = order.CreatedAt,
                    DeliveryType = order.DeliveryType,
                    Status = order.Status,
                    CustomerName = string.IsNullOrWhiteSpace(order.CustomerName) ? "--" : order.CustomerName,
                    ItemsSummary = BuildItemSummary(order.Id, itemsLookup),
                    Amount = ResolveDisplayAmount(order),
                    IsRefunded = isRefunded,
                    IsDimmed = order.Status == OrderStatus.Cancelled || isRefunded
                };
            })
            .ToList();

        return new PagedResult<OrderAllListItemDto>(rows, page, pageSize, totalCount);
    }

    private async Task<HashSet<long>> LoadRefundedOrderIdsAsync(
        IReadOnlyCollection<long> orderIds,
        long tenantId,
        CancellationToken cancellationToken)
    {
        if (orderIds.Count == 0)
        {
            return [];
        }

        var refunded = await orderRepository.GetRefundedOrderIdsAsync(orderIds, tenantId, cancellationToken);
        return refunded.ToHashSet();
    }

    private static decimal ResolveDisplayAmount(Order order)
    {
        return order.PaidAmount > 0 ? order.PaidAmount : order.PayableAmount;
    }

    private static string BuildItemSummary(
        long orderId,
        IReadOnlyDictionary<long, IReadOnlyList<OrderItem>> itemsLookup)
    {
        if (!itemsLookup.TryGetValue(orderId, out var items) || items.Count == 0)
        {
            return "--";
        }

        var first = string.IsNullOrWhiteSpace(items[0].ProductName) ? "商品" : items[0].ProductName.Trim();
        var totalQuantity = items.Sum(item => Math.Max(0, item.Quantity));
        if (totalQuantity <= 0)
        {
            totalQuantity = items.Count;
        }

        return $"{first}等{totalQuantity}件";
    }
}
