<?php
namespace Fifa\ConnectId\Sdk\Registration;

use DateTime;
use Fifa\ConnectId\Sdk\Api\Model\PersonDuplicateType;
use Fifa\ConnectId\Sdk\Api\Model\PersonType;
use Fifa\ConnectId\Sdk\Exception\FifaConnectIdException;
use Fifa\ConnectId\Sdk\Exception\InvalidClientDataException;
use Fifa\ConnectId\Sdk\Exception\TmsOperationException;
use Fifa\ConnectId\Sdk\FifaConnectIdClientInterface;
use Fifa\ConnectId\Sdk\MessageHandlers\MessageHandlerInterface;
use Fifa\ConnectId\Sdk\Model\DataStandard\PersonLocal;
use Fifa\ConnectId\Sdk\Model\PersonData;
use Fifa\ConnectId\Sdk\Model\PersonDuplicateWithDetails;
use Fifa\ConnectId\Sdk\Model\PersonName;
use Fifa\ConnectId\Sdk\Registration\Event\MessageEventHandlerInterface;
use Fifa\ConnectId\Sdk\Registration\Model\DuplicatesOfRegisteredPerson;
use Fifa\ConnectId\Sdk\Registration\Model\RegistrationResult;
use Fifa\ConnectId\Sdk\Registration\Model\UpdateResult;
use Fifa\ConnectServiceBus\Sdk\Exception\FifaConnectServiceBusSdkException;
use Fifa\ConnectServiceBus\Sdk\Exception\UnauthorizedException;
use Fifa\ConnectServiceBus\Sdk\FifaConnectServiceBusClientInterface;
use Fifa\ConnectServiceBus\Sdk\Exception\AuthenticationException;
use Psr\Log\LoggerInterface;
use Fifa\ConnectId\Sdk\Util\ToString\Exception\ToStringException;
use UnexpectedValueException;

/**
 * Interface RegistrationFacadeInterface
 * @package Fifa\ConnectId\Sdk\Registration
 */
interface RegistrationFacadeInterface
{
    /**
     * Sends requests for duplicates details
     *
     * @param PersonDuplicateType[] $duplicates - Collection of person duplicates
     * @param int $timeoutSeconds - Time to wait for duplicates details in seconds
     * @return mixed
     *
     * @throws ToStringException
     * @throws UnexpectedValueException
     */
    public function sendRequestsForDetailsAndWaitForThem(array $duplicates, int $timeoutSeconds);

    /**
     * Sends requests for duplicates details
     *
     * @param PersonDuplicateType[] $duplicates
     * @return mixed
     */
    public function sendRequestsForDetails(array $duplicates);

    /**
     * Registers a new person and assigns FIFA Unique Identifier.
     * If duplicates are found the person is not registered.
     * Uses 'PersonLocalType' as defined in FIFA Data Standard.
     *
     * @param PersonData $personData - Object containing information about local and international names of the person, as well as the date of birth.
     * @param string|null $personLocalId - Local identifier of person
     * @param int $timeoutSeconds - Time to wait for duplicates details.
     * @return RegistrationResult
     *
     * @throws AuthenticationException
     * @throws FifaConnectIdException
     * @throws InvalidClientDataException
     * @throws UnauthorizedException
     * @throws ToStringException
     * @throws UnexpectedValueException
     */
    public function registerPersonAndWaitForDetailsInCaseOfDuplicatesByGivingPersonData(PersonData $personData, int $timeoutSeconds, ?string $personLocalId): RegistrationResult;

    /**
     * Getter for serviceBusClient
     *
     * @return FifaConnectServiceBusClientInterface
     */
    public function getServiceBusClient(): FifaConnectServiceBusClientInterface;

    /**
     * Getter for connectIdClient
     *
     * @return FifaConnectIdClientInterface
     */
    public function getConnectIdClient(): FifaConnectIdClientInterface;

    /**
     * Getter for logger
     *
     * @return LoggerInterface
     */
    public function getLogger(): LoggerInterface;

    /**
     * Receive messages and store them in storage mechanism
     */
    public function receiveMessages();

    /**
     * Setup event handlers responsible for handling messages
     *
     * @param PersonDetailsProviderInterface $personDetailsProvider
     * @param MessageHandlerInterface[]|null $messageHandlers
     * @return MessageEventHandlerInterface
     */
    public function configureEventHandlers(PersonDetailsProviderInterface $personDetailsProvider, ?array $messageHandlers = null): MessageEventHandlerInterface;

    /**
     * Updates person data even if possible duplicates are found
     *
     * @param string $fifaId - Fifa identifier of person.
     * @param PersonName[] $names - Null if not changed
     * @param DateTime|null $dateOfBirth - Null if not changed
     * @param string|null $gender
     * @return PersonType
     */
    public function forceUpdatePerson(string $fifaId, ?array $names = null, ?DateTime $dateOfBirth = null, ?string $gender = null): PersonType;

    /**
     * Updates a person
     * If duplicates are found the person is not updated.
     *
     * @param string $fifaId
     * @param int $timeoutSeconds
     * @param PersonName[] $names - Null if not changed
     * @param DateTime|null $dateOfBirth - Null if not changed
     * @param string|null $gender
     * @return UpdateResult
     *
     * @throws ToStringException
     * @throws UnexpectedValueException
     */
    public function updatePersonAndWaitForDetailsInCaseOfDuplicates(string $fifaId, int $timeoutSeconds, ?array $names = null, ?DateTime $dateOfBirth = null, ?string $gender = null): UpdateResult;

    /**
     * Checks for duplicates of a person.
     * If duplicates are found, the details are requested by Connect Service Bus.
     *
     * @param PersonData $personData - Object containing information about local and international names of the person, as well as the date of birth.
     * @param int $timeoutSeconds - Time to wait for duplicates details.
     * @param string[]|null $organisationsIds - Organisations FIFA Unique Identifiers
     * @return PersonDuplicateWithDetails[]
     *
     * @throws InvalidClientDataException
     * @throws FifaConnectIdException
     * @throws AuthenticationException
     * @throws UnauthorizedException
     *
     * @deprecated Method getDuplicatesAndWaitForDetailsInCaseOfDuplicates is obsolete. Use getDuplicates instead.
     */
    public function getDuplicatesAndWaitForDetailsInCaseOfDuplicates(PersonData $personData, int $timeoutSeconds, ?array $organisationsIds = null): array;

    /**
     * Checks for duplicates of a person.
     * If duplicates are found, the details are requested by Connect Service Bus.
     *
     * @param PersonData $personData - Object containing information about local and international names of the person, as well as the date of birth.
     * @param int $timeoutSeconds - Time to wait for duplicates details.
     * @param string[]|null $organisationsIds - Organisations FIFA Unique Identifiers
     * @return PersonDuplicateWithDetails[]
     *
     * @throws InvalidClientDataException
     * @throws FifaConnectIdException
     * @throws AuthenticationException
     * @throws UnauthorizedException
     * @throws ToStringException
     * @throws UnexpectedValueException
     */
    public function getDuplicates(PersonData $personData, int $timeoutSeconds, ?array $organisationsIds = null): array;

    /**
     * Checks for duplicates of a person.
     * If duplicates are found, the details are requested by Connect Service Bus.
     * Duplicates marked as known duplicate by trusted organisations would not be returned.
     *
     * @param string $personFifaId - Person FIFA Unique Identifier.
     * @param int $timeoutSeconds - Time to wait for duplicates details.
     * @param string[]|null $trustedOrganisationsIds - Trusted organisations' FIFA Unique Identifiers
     * @return DuplicatesOfRegisteredPerson
     *
     * @throws InvalidClientDataException
     * @throws FifaConnectIdException
     * @throws AuthenticationException
     * @throws UnauthorizedException
     */
    public function getDuplicatesExceptTrustedKnownDuplicates(string $personFifaId, int $timeoutSeconds, ?array $trustedOrganisationsIds = null): DuplicatesOfRegisteredPerson;

    /**
     * Registers a new person even if possible duplicates are found.
     * Uses 'PersonLocalType' as defined in FIFA Data Standard.
     *
     * @param PersonData $personData - object containing information about local and international names of the person, as well as the date of birth.
     * @param string|null $personLocalId - Local identifier of person
     * @return string
     *
     * @throws InvalidClientDataException
     * @throws FifaConnectIdException
     * @throws UnauthorizedException
     * @throws AuthenticationException
     */
    public function forceRegisterPerson(PersonData $personData, ?string $personLocalId = null): string;
}
