<?php

namespace FiloBlu\Storelocator\Model;

use FiloBlu\Core\Framework\Model\AbstractSqlRepository;
use FiloBlu\Storelocator\Api\Data\EventsInterface;
use FiloBlu\Storelocator\Api\Data\EventsInterfaceFactory;
use FiloBlu\Storelocator\Api\EventsRepositoryInterface;
use Magento\Framework\Api\ExtensibleDataInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Api\SearchResultsInterfaceFactory;
use Magento\Framework\Api\Search\SearchCriteriaInterfaceFactory;
use Magento\Framework\App\ResourceConnection;

/**
 * Class EventsRepository
 * @package FiloBlu\Storelocator\Model
 */
class EventsRepository extends AbstractSqlRepository implements EventsRepositoryInterface
{
    /** @var string */
    const TABLE_NAME = 'filoblu_storelocator_events';

    /**
     * @var EventsFactory
     */
    private $eventsFactory;

    /**
     * @var SearchCriteriaBuilder
     */
    private $searchCriteriaBuilder;

    /**
     * @param ResourceConnection $resourceConnection
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     * @param SearchCriteriaInterfaceFactory $searchCriteriaFactory
     * @param SearchResultsInterfaceFactory $searchResultsFactory
     * @param EventsInterfaceFactory $eventsFactory
     */
    public function __construct(
        ResourceConnection $resourceConnection,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        SearchCriteriaInterfaceFactory $searchCriteriaFactory,
        SearchResultsInterfaceFactory $searchResultsFactory,
        EventsInterfaceFactory $eventsFactory
    ) {
        parent::__construct($resourceConnection, $searchCriteriaFactory, $searchResultsFactory);
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        $this->eventsFactory = $eventsFactory;
    }

    public function getTable(): string
    {
        return self::TABLE_NAME;
    }

    public function getIdFieldName(): string
    {
        return EventsInterface::ROW_ID;
    }

    /**
     * @param array $row
     * @return mixed
     */
    public function fromRow(array $row)
    {
        /** @var EventsInterface $event */
        $event = $this->eventsFactory->create();

        return $event->setCountry($row[EventsInterface::COUNTRY])->setExternalEventId(
            $row[EventsInterface::EXTERNAL_EVENT_ID]
        )->setCategoryId($row[EventsInterface::CATEGORY_ID])->setName($row[EventsInterface::NAME])->setStart(
            $row[EventsInterface::START]
        )->setEnd($row[EventsInterface::END])->setLastUpdate($row[EventsInterface::LAST_UPDATE])->setEventId(
            $row[EventsInterface::EVENT_ID]
        );
    }

    /**
     * @param EventsInterface $event
     * @return EventsInterface
     */
    public function save(EventsInterface $event): EventsInterface
    {
        $connection = $this->resourceConnection->getConnection();
        $table = $connection->getTableName(self::TABLE_NAME);
        $externalId = $event->getExternalEventId();
        $bindings = [
            EventsInterface::STORE_ID => $event->getStoreId(),
            EventsInterface::COUNTRY => $event->getCountry(),
            EventsInterface::EXTERNAL_EVENT_ID => $externalId,
            EventsInterface::CATEGORY_ID => $event->getCategoryId(),
            EventsInterface::NAME => $event->getName(),
            EventsInterface::START => $event->getStart(),
            EventsInterface::END => $event->getEnd(),
            EventsInterface::LAST_UPDATE => $event->getLastUpdate(),
        ];

        $whereCondition = sprintf('%s = %s', EventsInterface::EXTERNAL_EVENT_ID, $externalId);

        if ($externalId && $connection->fetchOne(
            $connection->select()->from($table)->where($whereCondition)
        )) {
            $connection->update($table, $bindings, $whereCondition);
            return $event;
        }

        $connection->insert($table, $bindings);
        $event->setId($connection->lastInsertId($table));

        return $event;
    }

    /**
     * @param $externalId
     * @return false|ExtensibleDataInterface|null
     */
    public function getEventByExternalId($externalId)
    {
        $searchCriteria = $this->searchCriteriaBuilder->addFilter('external_event_id', $externalId)->create();

        return current($this->getList($searchCriteria)->getItems()) ?: null;
    }
}
