using CashLineERP.Contracts.Finance;

namespace CashLineERP.Application.Finance;

public sealed class PaymentGatewayExecutionService : IPaymentGatewayExecutionService
{
    private readonly IPaymentGatewayExecutionRepository _repository;

    public PaymentGatewayExecutionService(IPaymentGatewayExecutionRepository repository)
    {
        _repository = repository;
    }

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

    public PaymentGatewayExecutionResponse? GetExecution(long paymentGatewayExecutionId)
    {
        var execution = _repository.GetExecution(paymentGatewayExecutionId);
        return execution is null ? null : Map(execution);
    }

    public IReadOnlyCollection<PaymentGatewayExecutionResponse> GetCustomerCollectionExecutions(long customerPaymentRequestId) =>
        _repository.GetExecutionsForSourceDocument("CUSTOMER_PAYMENT_REQUEST", customerPaymentRequestId).Select(Map).ToArray();

    public PaymentGatewayExecutionResponse QueueCustomerCollection(long customerPaymentRequestId, long actorUserId) =>
        Map(_repository.QueueCustomerCollection(customerPaymentRequestId, actorUserId));

    public IReadOnlyCollection<PaymentGatewayExecutionResponse> GetSupplierPayoutExecutions(long accountsPayablePaymentId) =>
        _repository.GetExecutionsForSourceDocument("AP_PAYMENT", accountsPayablePaymentId).Select(Map).ToArray();

    public PaymentGatewayExecutionResponse QueueSupplierPayout(long accountsPayablePaymentId, string integrationProviderCode, long actorUserId) =>
        Map(_repository.QueueSupplierPayout(accountsPayablePaymentId, integrationProviderCode, actorUserId));

    public IReadOnlyCollection<PaymentGatewayExecutionResponse> GetRefundExecutions(long customerRefundId) =>
        _repository.GetExecutionsForSourceDocument("CUSTOMER_REFUND", customerRefundId).Select(Map).ToArray();

    public PaymentGatewayExecutionResponse QueueCustomerRefund(long customerRefundId, long actorUserId) =>
        Map(_repository.QueueCustomerRefund(customerRefundId, actorUserId));

    public PaymentGatewayProviderContractResponse GetCustomerCollectionProviderContract(long customerPaymentRequestId) =>
        Map(_repository.GetCustomerCollectionProviderContract(customerPaymentRequestId));

    public PaymentGatewayProviderContractResponse GetSupplierPayoutProviderContract(long accountsPayablePaymentId, string? integrationProviderCode = null) =>
        Map(_repository.GetSupplierPayoutProviderContract(accountsPayablePaymentId, integrationProviderCode));

    public PaymentGatewayProviderContractResponse GetCustomerRefundProviderContract(long customerRefundId) =>
        Map(_repository.GetCustomerRefundProviderContract(customerRefundId));

    public PaymentGatewayProviderContractResponse GetExecutionProviderStatusContract(long paymentGatewayExecutionId) =>
        Map(_repository.GetExecutionProviderStatusContract(paymentGatewayExecutionId));

    public PaymentGatewayProviderContractResponse GetExecutionProviderCancelContract(long paymentGatewayExecutionId) =>
        Map(_repository.GetExecutionProviderCancelContract(paymentGatewayExecutionId));

    public DispatchPaymentGatewayExecutionBatchResultResponse DispatchPendingExecutions(DispatchPaymentGatewayExecutionBatchRequest request) =>
        Map(_repository.DispatchPendingExecutions(new DispatchPaymentGatewayExecutionBatchCommand(
            request.ProcessorCode,
            request.BatchSize,
            request.PaymentChannelConfigurationId)));

    private static PaymentGatewayExecutionResponse Map(PaymentGatewayExecutionView execution) =>
        new(
            execution.PaymentGatewayExecutionId,
            execution.ExecutionNumber,
            execution.PaymentChannelConfigurationId,
            execution.ChannelCode,
            execution.ChannelName,
            execution.IntegrationEndpointId,
            execution.EndpointCode,
            execution.IntegrationProviderCode,
            execution.SourceDocumentType,
            execution.SourceDocumentId,
            execution.SourceDocumentNumber,
            execution.PartyId,
            execution.CurrencyCode,
            execution.AmountAmount,
            execution.CorrelationKey,
            execution.StatusCode,
            execution.ProviderReference,
            execution.ProviderStatusCode,
            execution.ProviderResponseText,
            execution.AttemptNumber,
            execution.DispatchedAtUtc,
            execution.DispatchedByProcess,
            execution.CompletedAtUtc,
            execution.LastErrorText,
            execution.CreatedAtUtc);

    private static PaymentGatewayProviderContractResponse Map(PaymentGatewayProviderContractView contract) =>
        new(
            contract.IntegrationProviderCode,
            contract.ContractTypeCode,
            contract.HttpMethodCode,
            contract.RequestUrl,
            contract.CallbackUrl,
            contract.AuthenticationModeCode,
            contract.CorrelationKey,
            contract.IdempotencyKey,
            contract.ProviderReference,
            contract.RequestBodyJson);

    private static DispatchPaymentGatewayExecutionBatchResultResponse Map(DispatchPaymentGatewayExecutionBatchResultView result) =>
        new(
            result.ProcessorCode,
            result.RequestedBatchSize,
            result.DispatchedCount,
            result.Executions.Select(Map).ToArray());
}
