using CashLineERP.Contracts.Integration;

namespace CashLineERP.Application.Integration;

public sealed class InboxMessageService : IInboxMessageService
{
    private readonly IInboxMessageRepository _repository;

    public InboxMessageService(IInboxMessageRepository repository)
    {
        _repository = repository;
    }

    public IReadOnlyCollection<InboxMessageResponse> GetInboxMessages(string? statusCode = null, string? integrationProviderCode = null) =>
        _repository.GetInboxMessages(statusCode, integrationProviderCode)
            .Select(Map)
            .ToArray();

    public InboxMessageResponse? GetInboxMessage(long inboxMessageId)
    {
        var message = _repository.GetInboxMessage(inboxMessageId);
        return message is null ? null : Map(message);
    }

    public InboxMessageResponse? FindExistingMessage(long integrationEndpointId, string? externalMessageId, string? correlationKey)
    {
        var message = _repository.FindExistingMessage(integrationEndpointId, externalMessageId, correlationKey);
        return message is null ? null : Map(message);
    }

    public InboxMessageResponse ReceiveInboxMessage(long actorUserId, ReceiveInboxMessageRequest request) =>
        Map(_repository.Receive(new ReceiveInboxMessageCommand(
            actorUserId,
            request.IntegrationEndpointId,
            request.MessageType,
            request.ExternalMessageId,
            request.CorrelationKey,
            request.PayloadText)));

    public ProcessInboxBatchResultResponse ProcessPendingMessages(ProcessInboxBatchRequest request)
    {
        var result = _repository.ProcessPendingMessages(new ProcessInboxBatchCommand(
            request.ProcessorCode,
            request.BatchSize,
            request.ExcludedIntegrationProviderCodes));

        return new ProcessInboxBatchResultResponse(
            result.ProcessorCode,
            result.RequestedBatchSize,
            result.ProcessedCount,
            result.ProcessedMessages.Select(Map).ToArray());
    }

    public InboxMessageResponse MoveInboxMessageToDeadLetter(long inboxMessageId, long actorUserId, DeadLetterQueueItemRequest request) =>
        Map(_repository.MoveToDeadLetter(inboxMessageId, actorUserId, request.ReasonText));

    public InboxMessageResponse ReplayInboxMessage(long inboxMessageId, long actorUserId, ReplayDeadLetterQueueItemRequest request) =>
        Map(_repository.Replay(inboxMessageId, actorUserId, request.ReplayReasonText, request.DelaySeconds));

    private static InboxMessageResponse Map(InboxMessageDetailView message) =>
        new(
            message.InboxMessageId,
            message.MessageNumber,
            message.IntegrationEndpointId,
            message.EndpointCode,
            message.IntegrationProviderCode,
            message.EnvironmentCode,
            message.MaxRetryCount,
            message.MessageType,
            message.ExternalMessageId,
            message.CorrelationKey,
            message.PayloadText,
            message.StatusCode,
            message.AttemptNumber,
            message.AvailableAtUtc,
            message.ProcessedAtUtc,
            message.ProcessedByProcess,
            message.LastErrorText,
            message.CreatedAtUtc,
            message.CreatedByUserId);
}
