<?php

namespace Fifa\ConnectId\Sdk\ApiClient\Tms;

use Fifa\ConnectId\Sdk\Exception\TmsOperationException;
use Fifa\ConnectId\Sdk\Model\DataStandard\PersonLocal;
use Fifa\ConnectId\Sdk\Model\Transfer\DomesticTransferDeclaration;
use Fifa\ConnectId\Sdk\Model\Transfer\FirstProRegistration;
use Fifa\ConnectId\Sdk\Model\Transfer\ProofOfPayment;
use Fifa\ConnectId\Sdk\Tms\TmsOperation;
use Fifa\ConnectId\Sdk\Tms\Validators\DomesticTransferDeclarationValidator;
use Fifa\ConnectId\Sdk\Tms\Validators\FirstProRegistrationValidator;
use Fifa\ConnectId\Sdk\Tms\Validators\PersonLocalValidator;
use Fifa\ConnectId\Sdk\Tms\Validators\ProofOfPaymentValidator;
use Fifa\ConnectId\Sdk\Util\Data\Message\TmsActionType;
use Fifa\ConnectId\Sdk\Util\MessageSerializers\DomesticTransferDeclarationXmlSerializer;
use Fifa\ConnectId\Sdk\Util\MessageSerializers\FirstProRegistrationXmlSerializer;
use Fifa\ConnectId\Sdk\Util\MessageSerializers\ProofOfPaymentXmlSerializer;
use Fifa\ConnectId\Sdk\Util\PersonLocalXmlSerializer\PersonLocalXmlSerializer;
use Fifa\ConnectServiceBus\Sdk\FifaConnectServiceBusClientInterface;
use Psr\Log\LoggerInterface;

/**
 * Class TmsApi
 * @package Fifa\ConnectId\Sdk\ApiClient\Tms
 */
class TmsApi implements TmsApiInterface
{
    /**
     * @var TmsOperation
     */
    private $personOperation;

    /**
     * @var TmsOperation
     */
    private $domesticTransferDeclarationOperation;

    /**
     * @var TmsOperation
     */
    private $proofOfPaymentOperation;

    /**
     * @var TmsOperation
     */
    private $firstProRegistrationOperation;

    /**
     * @param FifaConnectServiceBusClientInterface $serviceBusClient
     * @param LoggerInterface $logger
     * @internal
     * TmsApi constructor.
     */
    public function __construct(FifaConnectServiceBusClientInterface $serviceBusClient, LoggerInterface $logger)
    {
        $this->personOperation = new TmsOperation($serviceBusClient,
            function ($_, PersonLocal $personLocal) {
                PersonLocalValidator::validate($personLocal);
            },
            function (PersonLocal $personLocal) {
                $serializer = new PersonLocalXmlSerializer();
                return $serializer->serialize($personLocal);
            },
            function (PersonLocal $personLocal) {
                return sprintf('PersonLocal (FIFA_ID=%s)', $personLocal->PersonFIFAId);
            },
            $logger);

        $this->domesticTransferDeclarationOperation = new TmsOperation($serviceBusClient,
            function ($_, DomesticTransferDeclaration $domesticTransferDeclaration) {
                $validator = DomesticTransferDeclarationValidator::getInstance();
                $validator::validate($domesticTransferDeclaration);
            },
            function (DomesticTransferDeclaration $domesticTransferDeclaration) {
                $serializer = new DomesticTransferDeclarationXmlSerializer();
                return $serializer->serialize($domesticTransferDeclaration);
            },
            function (DomesticTransferDeclaration $domesticTransferDeclaration) {
                return sprintf('DomesticTransferDeclaration (Player\'s FIFA_ID=%s)', $domesticTransferDeclaration->PersonLocal->PersonFIFAId);
            },
            $logger);

        $this->proofOfPaymentOperation = new TmsOperation($serviceBusClient,
            function ($_, ProofOfPayment $proofOfPayment) {
                ProofOfPaymentValidator::validate($proofOfPayment);
            },
            function (ProofOfPayment $proofOfPayment) {
                $serializer = new ProofOfPaymentXmlSerializer();
                return $serializer->serialize($proofOfPayment);
            },
            function (ProofOfPayment $proofOfPayment) {
                return sprintf('ProofOfPayment (TMS Transfer ID = %s, PaymentType = %s)', $proofOfPayment->TmsTransferId, $proofOfPayment->PaymentType);
            },
            $logger);

        $this->firstProRegistrationOperation = new TmsOperation($serviceBusClient,
            function ($_, FirstProRegistration $firstProRegistration) {
                FirstProRegistrationValidator::validate($firstProRegistration);
            },
            function (FirstProRegistration $firstProRegistration) {
                $serializer = new FirstProRegistrationXmlSerializer();
                return $serializer->serialize($firstProRegistration);
            },
            function (FirstProRegistration $firstProRegistration) {
                return sprintf('FirstProRegistration (Player\'s FIFA_ID=%s)', $firstProRegistration->Player->PersonFIFAId);
            },
            $logger);
    }

    /**
     * @inheritDoc
     */
    public function addPlayer(string $correlationId, PersonLocal $personLocal): void
    {
        $this->personOperation->sendRequest($correlationId, TmsActionType::ADD_PLAYER, $personLocal);
    }

    /**
     * @inheritDoc
     */
    public function updatePlayer(string $correlationId, PersonLocal $personLocal): void
    {
        $this->personOperation->sendRequest($correlationId, TmsActionType::UPDATE_PLAYER, $personLocal);
    }

    /**
     * @inheritDoc
     */
    public function declareDomesticTransfer(string $correlationId, DomesticTransferDeclaration $declaration): void
    {
        $this->domesticTransferDeclarationOperation->sendRequest($correlationId, TmsActionType::DOMESTIC_TRANSFER_DECLARATION, $declaration);
    }

    /**
     * @inheritDoc
     */
    public function provePayment(string $correlationId, ProofOfPayment $proofOfPayment): void
    {
        $this->proofOfPaymentOperation->sendRequest($correlationId, TmsActionType::PROOF_OF_PAYMENT, $proofOfPayment);
    }

    /**
     * @inheritDoc
     */
    public function declareFirstProRegistration(string $correlationId, FirstProRegistration $firstProRegistration): void
    {
        $this->firstProRegistrationOperation->sendRequest($correlationId, TmsActionType::FIRST_PRO_REGISTRATION, $firstProRegistration);
    }
}