using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Orders.Commands;
using TakeoutSaaS.Application.App.Orders.Dto;
using TakeoutSaaS.Application.Messaging;
using TakeoutSaaS.Application.Messaging.Abstractions;
using TakeoutSaaS.Application.Messaging.Events;
using TakeoutSaaS.Domain.Orders.Entities;
using TakeoutSaaS.Domain.Orders.Enums;
using TakeoutSaaS.Domain.Orders.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Ids;

namespace TakeoutSaaS.Application.App.Orders.Handlers;

/// <summary>
/// 接单命令处理器。
/// </summary>
public sealed class AcceptOrderCommandHandler(
    IOrderRepository orderRepository,
    IEventPublisher eventPublisher,
    IIdGenerator idGenerator,
    ILogger<AcceptOrderCommandHandler> logger)
    : IRequestHandler<AcceptOrderCommand, OrderBoardCardDto>
{
    /// <inheritdoc />
    public async Task<OrderBoardCardDto> Handle(AcceptOrderCommand request, CancellationToken cancellationToken)
    {
        // 1. 查找订单
        var order = await orderRepository.FindByIdAsync(request.OrderId, request.TenantId, cancellationToken)
            ?? throw new BusinessException(ErrorCodes.NotFound, "订单不存在");

        // 2. 校验状态
        if (order.Status != OrderStatus.AwaitingPreparation)
        {
            throw new BusinessException(ErrorCodes.BadRequest, $"当前状态 {order.Status} 不允许接单");
        }

        // 3. 更新状态
        var oldStatus = order.Status;
        order.Status = OrderStatus.InProgress;

        // 4. 写入状态流转记录
        var history = new OrderStatusHistory
        {
            Id = idGenerator.NextId(),
            OrderId = order.Id,
            TenantId = order.TenantId,
            Status = OrderStatus.InProgress,
            OperatorId = request.OperatorId,
            Notes = "商户接单",
            OccurredAt = DateTime.UtcNow
        };

        await orderRepository.UpdateOrderAsync(order, cancellationToken);
        await orderRepository.AddStatusHistoryAsync(history, cancellationToken);
        await orderRepository.SaveChangesAsync(cancellationToken);

        // 5. 发布状态变更事件
        await eventPublisher.PublishAsync(EventRoutingKeys.OrderStatusChanged, new OrderStatusChangedEvent
        {
            OrderId = order.Id,
            OrderNo = order.OrderNo,
            TenantId = order.TenantId,
            StoreId = order.StoreId,
            OldStatus = (int)oldStatus,
            NewStatus = (int)order.Status,
            Channel = (int)order.Channel,
            DeliveryType = (int)order.DeliveryType,
            CustomerName = order.CustomerName,
            PaidAmount = order.PaidAmount,
            OccurredAt = history.OccurredAt
        }, cancellationToken);

        // 6. 记录日志
        logger.LogInformation("接单 {OrderNo} ({OrderId})", order.OrderNo, order.Id);

        // 7. 返回看板卡片 DTO
        return MapToCardDto(order);
    }

    private static OrderBoardCardDto MapToCardDto(Order order) => new()
    {
        Id = order.Id,
        OrderNo = order.OrderNo,
        StoreId = order.StoreId,
        Channel = order.Channel,
        DeliveryType = order.DeliveryType,
        Status = order.Status,
        CustomerName = order.CustomerName,
        CustomerPhone = order.CustomerPhone,
        TableNo = order.TableNo,
        QueueNumber = order.QueueNumber,
        PaidAmount = order.PaidAmount,
        CreatedAt = order.CreatedAt
    };
}
