using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.Integration;

namespace CashLineERP.Application.Finance;

public sealed class GatewayCallbackService : IGatewayCallbackService
{
    private readonly IGatewayCallbackRepository _repository;

    public GatewayCallbackService(IGatewayCallbackRepository repository)
    {
        _repository = repository;
    }

    public IReadOnlyCollection<GatewayCallbackReceiptResponse> GetCallbacks(long paymentChannelConfigurationId, string? statusCode = null) =>
        _repository.GetCallbacks(paymentChannelConfigurationId, statusCode)
            .Select(Map)
            .ToArray();

    public GatewayCallbackReceiptResponse? GetCallback(long paymentChannelConfigurationId, long inboxMessageId)
    {
        var callback = _repository.GetCallback(paymentChannelConfigurationId, inboxMessageId);
        return callback is null ? null : Map(callback);
    }

    public GatewayCallbackReceiveResultResponse Receive(GatewayCallbackReceiveRequest request)
    {
        var result = _repository.Receive(new GatewayCallbackReceiveCommand(
            request.PaymentChannelConfigurationId,
            request.CallbackSignature,
            request.ExternalMessageId,
            request.CorrelationKey,
            request.MessageType,
            request.PayloadText));

        return new GatewayCallbackReceiveResultResponse(
            result.DecisionCode,
            result.Message,
            result.Callback is null ? null : Map(result.Callback));
    }

    public GatewayCallbackReceiptResponse ReplayCallback(long paymentChannelConfigurationId, long inboxMessageId, long actorUserId, ReplayDeadLetterQueueItemRequest request) =>
        Map(_repository.Replay(paymentChannelConfigurationId, inboxMessageId, actorUserId, request));

    public ProcessGatewayCallbackBatchResultResponse ProcessCallbacks(long paymentChannelConfigurationId, ProcessGatewayCallbackBatchRequest request)
    {
        var result = _repository.ProcessCallbacks(new ProcessGatewayCallbackBatchCommand(
            paymentChannelConfigurationId,
            request.ProcessorCode,
            request.BatchSize));

        return new ProcessGatewayCallbackBatchResultResponse(
            result.PaymentChannelConfigurationId,
            result.ProcessorCode,
            result.RequestedBatchSize,
            result.ProcessedCount,
            result.UpdatedExecutionCount,
            result.SettlementMutationCount,
            result.PaymentGatewayExecutionIds,
            result.SettlementBatchIds);
    }

    private static GatewayCallbackReceiptResponse Map(GatewayCallbackReceiptView callback) =>
        new(
            callback.InboxMessageId,
            callback.MessageNumber,
            callback.PaymentChannelConfigurationId,
            callback.ChannelCode,
            callback.ChannelName,
            callback.IntegrationProviderCode,
            callback.IntegrationEndpointId,
            callback.EndpointCode,
            callback.MessageType,
            callback.ExternalMessageId,
            callback.CorrelationKey,
            callback.PayloadText,
            callback.StatusCode,
            callback.AttemptNumber,
            callback.AvailableAtUtc,
            callback.ProcessedAtUtc,
            callback.ProcessedByProcess,
            callback.LastErrorText,
            callback.CreatedAtUtc);
}
