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.Domain.Payments.Enums;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Orders.Handlers;

/// <summary>
/// 全部订单详情查询处理器。
/// </summary>
public sealed class GetOrderAllDetailQueryHandler(
    IOrderRepository orderRepository,
    ITenantProvider tenantProvider)
    : IRequestHandler<GetOrderAllDetailQuery, OrderAllDetailDto?>
{
    /// <inheritdoc />
    public async Task<OrderAllDetailDto?> Handle(GetOrderAllDetailQuery request, CancellationToken cancellationToken)
    {
        var tenantId = tenantProvider.GetCurrentTenantId();
        var orderNo = request.OrderNo.Trim();
        if (string.IsNullOrWhiteSpace(orderNo))
        {
            return null;
        }

        var order = await orderRepository.FindByOrderNoAsync(orderNo, tenantId, cancellationToken);
        if (order is null)
        {
            return null;
        }

        if (request.StoreId.HasValue && order.StoreId != request.StoreId.Value)
        {
            return null;
        }

        var items = await orderRepository.GetItemsAsync(order.Id, tenantId, cancellationToken);
        var histories = await orderRepository.GetStatusHistoryAsync(order.Id, tenantId, cancellationToken);
        var payment = await orderRepository.GetLatestPaymentRecordAsync(order.Id, tenantId, cancellationToken);
        var delivery = await orderRepository.GetLatestDeliveryOrderAsync(order.Id, tenantId, cancellationToken);

        return new OrderAllDetailDto
        {
            OrderId = order.Id,
            OrderNo = order.OrderNo,
            StoreId = order.StoreId,
            DeliveryType = order.DeliveryType,
            Status = order.Status,
            PaymentMethod = payment?.Method ?? PaymentMethod.Unknown,
            CustomerName = string.IsNullOrWhiteSpace(order.CustomerName) ? "--" : order.CustomerName,
            CustomerPhone = string.IsNullOrWhiteSpace(order.CustomerPhone) ? "--" : order.CustomerPhone,
            CustomerAddress = "--",
            ItemsAmount = order.ItemsAmount,
            DeliveryFee = delivery?.DeliveryFee ?? 0,
            DiscountAmount = order.DiscountAmount,
            PayableAmount = order.PayableAmount,
            PaidAmount = ResolveDisplayAmount(order),
            OrderedAt = order.CreatedAt,
            PaidAt = order.PaidAt,
            FinishedAt = order.FinishedAt,
            CancelledAt = order.CancelledAt,
            Remark = order.Remark?.Trim() ?? string.Empty,
            Items = items.Select(item => new OrderAllDetailItemDto
            {
                Name = string.IsNullOrWhiteSpace(item.ProductName) ? "--" : item.ProductName,
                Spec = string.IsNullOrWhiteSpace(item.SkuName) ? "标准" : item.SkuName,
                Quantity = item.Quantity,
                UnitPrice = item.UnitPrice,
                SubTotal = item.SubTotal
            }).ToList(),
            Timeline = BuildTimeline(order, histories)
        };
    }

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

    private static IReadOnlyList<OrderAllTimelineNodeDto> BuildTimeline(
        Order order,
        IReadOnlyList<OrderStatusHistory> histories)
    {
        var nodes = histories
            .OrderBy(history => history.OccurredAt)
            .Select(history => new OrderAllTimelineNodeDto
            {
                Label = ToTimelineLabel(history.Status, order.DeliveryType),
                OccurredAt = history.OccurredAt
            })
            .ToList();

        if (nodes.Count > 0)
        {
            return nodes;
        }

        var fallback = new List<OrderAllTimelineNodeDto>
        {
            new()
            {
                Label = "下单",
                OccurredAt = order.CreatedAt
            }
        };

        if (order.PaidAt.HasValue)
        {
            fallback.Add(new OrderAllTimelineNodeDto
            {
                Label = "支付成功",
                OccurredAt = order.PaidAt.Value
            });
        }

        if (order.FinishedAt.HasValue)
        {
            fallback.Add(new OrderAllTimelineNodeDto
            {
                Label = "已完成",
                OccurredAt = order.FinishedAt.Value
            });
        }

        if (order.CancelledAt.HasValue)
        {
            fallback.Add(new OrderAllTimelineNodeDto
            {
                Label = "已取消",
                OccurredAt = order.CancelledAt.Value
            });
        }

        return fallback
            .OrderBy(item => item.OccurredAt)
            .ToList();
    }

    private static string ToTimelineLabel(OrderStatus status, DeliveryType deliveryType)
    {
        return status switch
        {
            OrderStatus.PendingPayment => "下单",
            OrderStatus.AwaitingPreparation => "商家接单",
            OrderStatus.InProgress => "制作中",
            OrderStatus.Ready => ToReadyStatusText(deliveryType),
            OrderStatus.Completed => "已完成",
            OrderStatus.Cancelled => "已取消",
            _ => "状态变更"
        };
    }

    private static string ToReadyStatusText(DeliveryType deliveryType)
    {
        return deliveryType switch
        {
            DeliveryType.Delivery => "配送中",
            DeliveryType.Pickup => "待取餐",
            DeliveryType.DineIn => "待取餐",
            _ => "待处理"
        };
    }
}
