<?php

namespace Autogedal\FbReviews\Model;

use Autogedal\FbReviews\Api\Data\FbReviewInterface;
use Autogedal\FbReviews\Api\FbReviewRepositoryInterface;
use Autogedal\FbReviews\Model\FbReviewFactory;
use Autogedal\FbReviews\Model\ResourceModel\FbReview as FbReviewResource;
use Autogedal\FbReviews\Model\ResourceModel\FbReview\CollectionFactory;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Exception\CouldNotDeleteException;

class FbReviewRepository implements FbReviewRepositoryInterface
{
    /**
     * @var FbReviewFactory
     */
    private $fbReviewFactory;

    /**
     * @var FbReviewResource
     */
    private $fbReviewResource;

    /**
     * @var CollectionFactory
     */
    private $collectionFactory;

    /**
     * Model data storage
     *
     * @var array
     */
    private $fbReviews;

    public function __construct(
        FbReviewFactory $fbReviewFactory,
        FbReviewResource $fbReviewResource,
        CollectionFactory $collectionFactory
    ) {
        $this->fbReviewFactory = $fbReviewFactory;
        $this->fbReviewResource = $fbReviewResource;
        $this->collectionFactory = $collectionFactory;
    }

    /**
     * @inheritdoc
     */
    public function save(FbReviewInterface $fbReview)
    {
        try {
            if ($fbReview->getEntityId()) {
                $fbReview = $this->getById($fbReview->getEntityId())->addData($fbReview->getData());
            }
            $this->fbReviewResource->save($fbReview);
            unset($this->fbReviews[$fbReview->getEntityId()]);
        } catch (\Exception $e) {
            if ($fbReview->getEntityId()) {
                throw new CouldNotSaveException(
                    __(
                        'Unable to save Review with ID %1. Error: %2',
                        [$fbReview->getEntityId(), $e->getMessage()]
                    )
                );
            }
            throw new CouldNotSaveException(__('Unable to save new Facebook Review. Error: %1', $e->getMessage()));
        }

        return $fbReview;
    }

    /**
     * @inheritdoc
     */
    public function getById($fbReviewId)
    {
        if (!isset($this->fbReviews[$fbReviewId])) {
            $fbReview = $this->fbReviewFactory->create();
            $this->fbReviewResource->load($fbReview, $fbReviewId);
            if (!$fbReview->getEntityId()) {
                throw new NoSuchEntityException(__('Facebook Review with specified ID "%1" not found.', $fbReviewId));
            }
            $this->fbReviews[$fbReviewId] = $fbReview;
        }

        return $this->fbReviews[$fbReviewId];
    }

    /**
     * @inheritdoc
     */
    public function delete(FbReviewInterface $fbReview)
    {
        try {
            $this->fbReviewResource->delete($fbReview);
            unset($this->fbReviews[$fbReview->getEntityId()]);
        } catch (\Exception $e) {
            if ($fbReview->getEntityId()) {
                throw new CouldNotDeleteException(
                    __(
                        'Unable to remove Review with ID %1. Error: %2',
                        [$fbReview->getEntityId(), $e->getMessage()]
                    )
                );
            }
            throw new CouldNotDeleteException(__('Unable to remove Review. Error: %1', $e->getMessage()));
        }

        return true;
    }

    /**
     * @inheritdoc
     */
    public function deleteById($fbReviewId)
    {
        $fbModel = $this->getById($fbReviewId);
        $this->delete($fbModel);

        return true;
    }

    /**
     * @param int[] $fbReviewIds
     *
     * @return FbReviewInterface[]
     */
    public function getListByIds($fbReviewIds)
    {
        $idsToLoad = $result = [];
        foreach ($fbReviewIds as $fbReviewId) {
            if (isset($this->fbReviews[$fbReviewId])) {
                $result[$fbReviewId] = $this->fbReviews[$fbReviewId];
            } else {
                $idsToLoad[] = $fbReviewId;
            }
        }
        if (!empty($idsToLoad)) {
            $collection = $this->collectionFactory->create();
            $collection
                ->addFieldToFilter(FbReviewInterface::ENTITY_ID, ['in' => $idsToLoad]);

            foreach ($collection->getItems() as $fbReview) {
                $this->fbReviews[$fbReview->getId()] = $fbReview;
                $result[$fbReview->getId()] = $fbReview;
            }
        }

        return $result;
    }
}
