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

namespace TakeoutSaaS.Application.App.Deliveries.Handlers;

/// <summary>
/// 更新配送单命令处理器。
/// </summary>
public sealed class UpdateDeliveryOrderCommandHandler(
    IDeliveryRepository deliveryRepository,
    ITenantProvider tenantProvider,
    ILogger<UpdateDeliveryOrderCommandHandler> logger)
    : IRequestHandler<UpdateDeliveryOrderCommand, DeliveryOrderDto?>
{
    /// <inheritdoc />
    public async Task<DeliveryOrderDto?> Handle(UpdateDeliveryOrderCommand request, CancellationToken cancellationToken)
    {
        // 1. 获取当前租户标识
        var tenantId = tenantProvider.GetCurrentTenantId();

        // 2. 查询目标配送单
        var existing = await deliveryRepository.FindByIdAsync(request.DeliveryOrderId, tenantId, cancellationToken);
        if (existing == null)
        {
            return null;
        }

        // 3. 更新字段
        existing.OrderId = request.OrderId;
        existing.Provider = request.Provider;
        existing.ProviderOrderId = request.ProviderOrderId?.Trim();
        existing.Status = request.Status;
        existing.DeliveryFee = request.DeliveryFee;
        existing.CourierName = request.CourierName?.Trim();
        existing.CourierPhone = request.CourierPhone?.Trim();
        existing.DispatchedAt = request.DispatchedAt;
        existing.PickedUpAt = request.PickedUpAt;
        existing.DeliveredAt = request.DeliveredAt;
        existing.FailureReason = request.FailureReason?.Trim();

        // 4. 持久化变更
        await deliveryRepository.UpdateDeliveryOrderAsync(existing, cancellationToken);
        await deliveryRepository.SaveChangesAsync(cancellationToken);

        // 5. 记录更新日志
        logger.LogInformation("更新配送单 {DeliveryOrderId}", existing.Id);

        // 6. 查询事件并返回映射结果
        var events = await deliveryRepository.GetEventsAsync(existing.Id, tenantId, cancellationToken);
        return MapToDto(existing, events);
    }

    private static DeliveryOrderDto MapToDto(DeliveryOrder deliveryOrder, IReadOnlyList<DeliveryEvent> events) => new()
    {
        Id = deliveryOrder.Id,
        TenantId = deliveryOrder.TenantId,
        OrderId = deliveryOrder.OrderId,
        Provider = deliveryOrder.Provider,
        ProviderOrderId = deliveryOrder.ProviderOrderId,
        Status = deliveryOrder.Status,
        DeliveryFee = deliveryOrder.DeliveryFee,
        CourierName = deliveryOrder.CourierName,
        CourierPhone = deliveryOrder.CourierPhone,
        DispatchedAt = deliveryOrder.DispatchedAt,
        PickedUpAt = deliveryOrder.PickedUpAt,
        DeliveredAt = deliveryOrder.DeliveredAt,
        FailureReason = deliveryOrder.FailureReason,
        CreatedAt = deliveryOrder.CreatedAt,
        Events = events.Select(x => new DeliveryEventDto
        {
            Id = x.Id,
            DeliveryOrderId = x.DeliveryOrderId,
            EventType = x.EventType,
            Message = x.Message,
            OccurredAt = x.OccurredAt,
            Payload = x.Payload
        }).ToList()
    };
}
