<?php

namespace Fifa\ConnectId\Sdk\Tms;

use Closure;
use Exception;
use Fifa\ConnectId\Sdk\Exception\TmsOperationException;
use Fifa\ConnectId\Sdk\Registration\PrefixedLogger;
use Fifa\ConnectId\Sdk\Util\CorrelationIdFormatter;
use Fifa\ConnectId\Sdk\Util\Data\Message\MessageProperties;
use Fifa\ConnectId\Sdk\Util\SdkVersionHelper;
use Fifa\ConnectServiceBus\Sdk\Exception\AuthenticationException;
use Fifa\ConnectServiceBus\Sdk\Exception\FifaConnectServiceBusSdkException;
use Fifa\ConnectServiceBus\Sdk\Exception\InvalidClientDataException;
use Fifa\ConnectServiceBus\Sdk\Exception\QueueNotFoundException;
use Fifa\ConnectServiceBus\Sdk\Exception\UnauthorizedException;
use Fifa\ConnectServiceBus\Sdk\FifaConnectServiceBusClientInterface;
use Fifa\ConnectServiceBus\Sdk\Message\Message;
use Psr\Log\LoggerInterface;

class TmsOperation
{
    /**
     * @var string
     */
    private static $tmsRecipient = '105C3ZB_TMS';

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var FifaConnectServiceBusClientInterface
     */
    private $serviceBusClient;

    /**
     * @var Closure
     */
    private $requestValidator;

    /**
     * @var Closure
     */
    private $requestSerializer;

    /**
     * @var Closure
     */
    private $requestToString;

    public function __construct(FifaConnectServiceBusClientInterface $serviceBusClient, Closure $requestValidator, Closure $requestSerializer, Closure $requestToString, LoggerInterface $logger)
    {
        $this->serviceBusClient = $serviceBusClient;
        $this->requestValidator = $requestValidator;
        $this->requestSerializer = $requestSerializer;
        $this->requestToString = $requestToString;
        $this->logger = $logger;
    }

    /**
     * @param string $correlationId
     * @param string $requestType
     * @param $request
     * @throws TmsOperationException
     */
    public function sendRequest(string $correlationId, string $requestType, $request): void
    {
        $requestLogger = new PrefixedLogger($this->logger,
            sprintf(CorrelationIdFormatter::format($correlationId).'[ReqType: %s] [Req: %s] ', $requestType, $this->requestToString->call($this, $request)));
        try {
            $this->requestValidator->call($this, $requestType, $request);

            $requestLogger->debug('Sending...');
            $this->sendMessage($correlationId, $requestType, $request);
            $requestLogger->debug('Sent.');
        } catch (Exception $ex) {
            throw new TmsOperationException('An issue occurred when trying to send the request.', 0, $ex);
        }
    }

    /**
     * @param string $correlationId
     * @param string $requestType
     * @param object $request
     * @throws AuthenticationException
     * @throws FifaConnectServiceBusSdkException
     * @throws InvalidClientDataException
     * @throws QueueNotFoundException
     * @throws UnauthorizedException
     */
    private function sendMessage(string $correlationId, string $requestType, $request)
    {
        $xml = $this->requestSerializer->call($this, $request);
        $properties = array(
            MessageProperties::CORRELATION_ID => $correlationId,
            MessageProperties::VERSION => SdkVersionHelper::getSdkVersion()
        );
        $message = new Message($xml, $requestType, $properties);
        $this->serviceBusClient->send(self::$tmsRecipient, $message);
    }
}