using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Orders.Commands;
using TakeoutSaaS.Application.App.Orders.Dto;
using TakeoutSaaS.Domain.Orders.Entities;
using TakeoutSaaS.Domain.Orders.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Orders.Handlers;

/// <summary>
/// 更新订单命令处理器。
/// </summary>
public sealed class UpdateOrderCommandHandler(
    IOrderRepository orderRepository,
    ITenantProvider tenantProvider,
    ILogger<UpdateOrderCommandHandler> logger)
    : IRequestHandler<UpdateOrderCommand, OrderDto?>
{
    /// <inheritdoc />
    public async Task<OrderDto?> Handle(UpdateOrderCommand request, CancellationToken cancellationToken)
    {
        // 1. 读取订单
        var tenantId = tenantProvider.GetCurrentTenantId();
        var existing = await orderRepository.FindByIdAsync(request.OrderId, tenantId, cancellationToken);
        if (existing == null)
        {
            return null;
        }

        // 2. 更新字段
        existing.OrderNo = request.OrderNo.Trim();
        existing.StoreId = request.StoreId;
        existing.Channel = request.Channel;
        existing.DeliveryType = request.DeliveryType;
        existing.Status = request.Status;
        existing.PaymentStatus = request.PaymentStatus;
        existing.CustomerName = request.CustomerName?.Trim();
        existing.CustomerPhone = request.CustomerPhone?.Trim();
        existing.TableNo = request.TableNo?.Trim();
        existing.QueueNumber = request.QueueNumber?.Trim();
        existing.ReservationId = request.ReservationId;
        existing.ItemsAmount = request.ItemsAmount;
        existing.DiscountAmount = request.DiscountAmount;
        existing.PayableAmount = request.PayableAmount;
        existing.PaidAmount = request.PaidAmount;
        existing.PaidAt = request.PaidAt;
        existing.FinishedAt = request.FinishedAt;
        existing.CancelledAt = request.CancelledAt;
        existing.CancelReason = request.CancelReason?.Trim();
        existing.Remark = request.Remark?.Trim();

        // 3. 持久化
        await orderRepository.UpdateOrderAsync(existing, cancellationToken);
        await orderRepository.SaveChangesAsync(cancellationToken);

        // 4. 记录更新日志
        logger.LogInformation("更新订单 {OrderNo} ({OrderId})", existing.OrderNo, existing.Id);

        // 5. 读取关联数据并返回
        var items = await orderRepository.GetItemsAsync(existing.Id, tenantId, cancellationToken);
        var histories = await orderRepository.GetStatusHistoryAsync(existing.Id, tenantId, cancellationToken);
        var refunds = await orderRepository.GetRefundsAsync(existing.Id, tenantId, cancellationToken);

        return MapToDto(existing, items, histories, refunds);
    }

    private static OrderDto MapToDto(
        Order order,
        IReadOnlyList<OrderItem> items,
        IReadOnlyList<OrderStatusHistory> histories,
        IReadOnlyList<RefundRequest> refunds) => new()
        {
            Id = order.Id,
            TenantId = order.TenantId,
            OrderNo = order.OrderNo,
            StoreId = order.StoreId,
            Channel = order.Channel,
            DeliveryType = order.DeliveryType,
            Status = order.Status,
            PaymentStatus = order.PaymentStatus,
            CustomerName = order.CustomerName,
            CustomerPhone = order.CustomerPhone,
            TableNo = order.TableNo,
            QueueNumber = order.QueueNumber,
            ReservationId = order.ReservationId,
            ItemsAmount = order.ItemsAmount,
            DiscountAmount = order.DiscountAmount,
            PayableAmount = order.PayableAmount,
            PaidAmount = order.PaidAmount,
            PaidAt = order.PaidAt,
            FinishedAt = order.FinishedAt,
            CancelledAt = order.CancelledAt,
            CancelReason = order.CancelReason,
            Remark = order.Remark,
            Items = items.Select(x => new OrderItemDto
            {
                Id = x.Id,
                OrderId = x.OrderId,
                ProductId = x.ProductId,
                ProductName = x.ProductName,
                SkuName = x.SkuName,
                Unit = x.Unit,
                Quantity = x.Quantity,
                UnitPrice = x.UnitPrice,
                DiscountAmount = x.DiscountAmount,
                SubTotal = x.SubTotal,
                AttributesJson = x.AttributesJson
            }).ToList(),
            StatusHistory = histories.Select(x => new OrderStatusHistoryDto
            {
                Id = x.Id,
                OrderId = x.OrderId,
                Status = x.Status,
                OperatorId = x.OperatorId,
                Notes = x.Notes,
                OccurredAt = x.OccurredAt
            }).ToList(),
            Refunds = refunds.Select(x => new RefundRequestDto
            {
                Id = x.Id,
                OrderId = x.OrderId,
                RefundNo = x.RefundNo,
                Amount = x.Amount,
                Reason = x.Reason,
                Status = x.Status,
                RequestedAt = x.RequestedAt,
                ProcessedAt = x.ProcessedAt,
                ReviewNotes = x.ReviewNotes
            }).ToList(),
            CreatedAt = order.CreatedAt
        };
}
