using CashLineERP.Contracts.Sales;

namespace CashLineERP.Application.Sales;

public sealed class DispatchOrderService : IDispatchOrderService
{
    private readonly IDispatchOrderRepository _repository;

    public DispatchOrderService(IDispatchOrderRepository repository)
    {
        _repository = repository;
    }

    public IReadOnlyCollection<DispatchOrderResponse> GetDispatchOrders() =>
        _repository.GetDispatchOrders().Select(Map).ToArray();

    public DispatchOrderResponse? GetDispatchOrder(long dispatchOrderId)
    {
        var dispatchOrder = _repository.GetDispatchOrder(dispatchOrderId);
        return dispatchOrder is null ? null : Map(dispatchOrder);
    }

    public DispatchOrderResponse CreateDispatchOrder(CreateDispatchOrderRequest request)
    {
        var dispatchOrder = _repository.Create(new CreateDispatchOrderCommand(
            request.BranchId,
            request.SalesOrderId,
            request.DispatchWarehouseId,
            request.PlannedShipAtUtc,
            request.Lines.Select(line => new CreateDispatchOrderLineCommand(
                line.SalesOrderLineId,
                line.ItemId,
                line.QuantityDispatched,
                line.WarehouseLocationId,
                line.BatchNumber,
                line.SerialNumber)).ToArray()));

        return Map(dispatchOrder);
    }

    public DispatchOrderResponse PostDispatchOrder(long dispatchOrderId, PostDispatchOrderRequest request) =>
        Map(_repository.Post(dispatchOrderId, request.ActorUserId, request.ShippedAtUtc, request.DeliveredAtUtc, request.ProofOfDeliveryReceiver));

    public DispatchOrderResponse RecordProofOfDelivery(long dispatchOrderId, long actorUserId, RecordProofOfDeliveryRequest request) =>
        Map(_repository.RecordProofOfDelivery(
            dispatchOrderId,
            actorUserId,
            request.DeliveredAtUtc ?? DateTime.UtcNow,
            request.ProofOfDeliveryReceiver,
            request.DeliveryConditionCode,
            request.ProofOfDeliveryReference,
            request.Notes));

    public DispatchOrderResponse RecordDeliveryException(long dispatchOrderId, long actorUserId, RecordDeliveryExceptionRequest request) =>
        Map(_repository.RecordDeliveryException(
            dispatchOrderId,
            actorUserId,
            request.DeliveredAtUtc ?? DateTime.UtcNow,
            request.DeliveryConditionCode,
            request.DeliveryExceptionCode,
            request.ProofOfDeliveryReceiver,
            request.ProofOfDeliveryReference,
            request.Notes,
            request.Lines.Select(line => (line.DispatchOrderLineId, line.QuantityFailed)).ToArray()));

    public DispatchOrderResponse RecoverFailedDelivery(long dispatchOrderId, long actorUserId, RecoverFailedDeliveryRequest request) =>
        Map(_repository.RecoverFailedDelivery(
            dispatchOrderId,
            actorUserId,
            request.RecoveredAtUtc ?? DateTime.UtcNow,
            request.Notes,
            request.Lines.Select(line => (line.DispatchOrderLineId, line.QuantityRecovered, line.WarehouseLocationId, line.RecoveredStockStatusCode)).ToArray()));

    private static DispatchOrderResponse Map(DispatchOrderDetailView dispatchOrder) =>
        new(
            dispatchOrder.DispatchOrderId,
            dispatchOrder.DispatchNumber,
            dispatchOrder.BranchId,
            dispatchOrder.SalesOrderId,
            dispatchOrder.DispatchWarehouseId,
            dispatchOrder.StatusCode,
            dispatchOrder.PlannedShipAtUtc,
            dispatchOrder.ShippedAtUtc,
            dispatchOrder.DeliveredAtUtc,
            dispatchOrder.ProofOfDeliveryReceiver,
            dispatchOrder.ProofOfDeliveryCapturedAtUtc,
            dispatchOrder.ProofOfDeliveryCapturedByUserId,
            dispatchOrder.DeliveryConditionCode,
            dispatchOrder.ProofOfDeliveryReference,
            dispatchOrder.ProofOfDeliveryNotes,
            dispatchOrder.DeliveryExceptionCode,
            dispatchOrder.DeliveryExceptionRecordedAtUtc,
            dispatchOrder.DeliveryExceptionRecordedByUserId,
            dispatchOrder.DeliveryExceptionNotes,
            dispatchOrder.DeliveryRecoveryStatusCode,
            dispatchOrder.DeliveryRecoveredAtUtc,
            dispatchOrder.DeliveryRecoveredByUserId,
            dispatchOrder.DeliveryRecoveryNotes,
            dispatchOrder.Lines.Select(line => new DispatchOrderLineResponse(
                line.DispatchOrderLineId,
                line.LineNumber,
                line.SalesOrderLineId,
                line.ItemId,
                line.QuantityDispatched,
                line.QuantityDelivered,
                line.QuantityFailed,
                line.QuantityRecovered,
                line.WarehouseLocationId,
                line.BatchNumber,
                line.SerialNumber)).ToArray());
}
