<?php

namespace FiloBlu\Esb\Model\Rest;

use Exception;
use FiloBlu\Esb\Api\Data\MessageInterfaceFactory;
use FiloBlu\Esb\Api\ObjectTypeServiceInterface;
use FiloBlu\Esb\Core\Extractor\ObjectTypeFromMessage;
use FiloBlu\Esb\Framework\Event\EventEmitter;
use FiloBlu\Esb\Model\EventResolver;
use FiloBlu\Esb\Model\ObjectTypeLoaderResolverInterface;
use Magento\Framework\DataObjectFactory;
use Magento\Framework\Exception\NoSuchEntityException;
use Psr\Log\LoggerInterface;
use Throwable;

/**
 * Class ObjectTypeService
 * @package FiloBlu\Esb\Model\Rest
 */
class ObjectTypeService implements ObjectTypeServiceInterface
{
    /**
     * @var EventEmitter
     */
    private $eventEmitter;
    /**
     * @var EventResolver
     */
    private $eventResolver;
    /**
     * @var ObjectTypeFromMessage
     */
    private $objectTypeFromMessage;
    /**
     * @var MessageInterfaceFactory
     */
    private $messageFactory;
    /**
     * @var DataObjectFactory
     */
    private $dataObjectFactory;
    /**
     * @var ObjectTypeLoaderResolverInterface
     */
    private $objectTypeLoaderResolver;
    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * ObjectTypeService constructor.
     * @param EventEmitter $eventEmitter
     * @param EventResolver $eventResolver
     * @param MessageInterfaceFactory $messageFactory
     * @param DataObjectFactory $dataObjectFactory
     * @param ObjectTypeFromMessage $objectTypeFromMessage
     * @param ObjectTypeLoaderResolverInterface $objectTypeLoaderResolver
     * @param LoggerInterface $logger
     */
    public function __construct(EventEmitter $eventEmitter,
                                EventResolver $eventResolver,
                                MessageInterfaceFactory $messageFactory,
                                DataObjectFactory $dataObjectFactory,
                                ObjectTypeFromMessage $objectTypeFromMessage,
                                ObjectTypeLoaderResolverInterface $objectTypeLoaderResolver,
                                LoggerInterface $logger)
    {
        $this->eventEmitter = $eventEmitter;
        $this->eventResolver = $eventResolver;
        $this->objectTypeFromMessage = $objectTypeFromMessage;
        $this->messageFactory = $messageFactory;
        $this->dataObjectFactory = $dataObjectFactory;
        $this->objectTypeLoaderResolver = $objectTypeLoaderResolver;
        $this->logger = $logger;
    }

    /**
     * @param string $event
     * @param mixed $message
     * @return void
     * @throws NoSuchEntityException
     * @throws Exception
     */
    public function push($event, $message)
    {
        $esbEvent = $this->eventResolver->get($event);
        $this->eventEmitter->emit($esbEvent, $this->getMessage($message));
    }

    /**
     * @param array|null $payload
     * @return mixed
     */
    public function getMessage($payload)
    {
        try {
            if ($this->objectTypeFromMessage->isObjectType($payload)) {
                $objectType = $this->objectTypeFromMessage->extract(
                    $this->messageFactory->create()->setPayload(
                        $this->dataObjectFactory->create(['data' => $payload])
                    )
                );

                return $this->objectTypeLoaderResolver->getFor($objectType)->get($objectType);
            }
        } catch (Throwable $throwable) {
            $this->logger->error($throwable->getMessage(), ['exception' => $throwable]);
            return $payload;
        }

        return $payload;
    }
}
