<?php
namespace Newland\Toubiz\Sync\Neos\Importer;

/*
 * This file is part of the "toubiz-sync-neos" package.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 */

use Neos\Flow\Annotations as Flow;
use Neos\Flow\ResourceManagement\Exception as ResourceManagementException;
use Neos\Flow\ResourceManagement\PersistentResource;
use Neos\Flow\ResourceManagement\ResourceManager;
use Newland\Toubiz\Api\ObjectAdapter\MediumAdapterInterface;
use Newland\Toubiz\Sync\Neos\Domain\Model\Medium;
use Newland\Toubiz\Sync\Neos\Domain\Repository\MediumRepository;

class MediumImporter extends AbstractImporter
{
    /**
     * @Flow\Inject()
     * @var MediumRepository
     */
    protected $mediumRepository;

    /**
     * @var ResourceManager
     * @Flow\Inject()
     */
    protected $resourceManager;

    /** @var bool */
    protected $download = true;

    public function setDownload(bool $download): void
    {
        $this->download = $download;
    }

    /**
     * Import method.
     *
     * Persist given data by creating new objects or updating existing ones.
     *
     * @param MediumAdapterInterface $data
     * @param Medium|null $medium
     * @return Medium
     */
    public function import($data, Medium $medium = null): ?Medium
    {
        $persisted = (bool) $medium;

        if (!$medium) {
            $medium = new Medium();
        }

        $medium->setOriginalId($data->getExternalId());
        $medium->setTitle($data->getTitle());
        $medium->setCopyright($data->getCopyright());
        $mapped = $this->mapImage($medium, $data);
        if (!$mapped) {
            return null;
        }

        if ($persisted) {
            $this->mediumRepository->update($medium);
        } else {
            $this->mediumRepository->add($medium);
        }

        return $medium;
    }

    private function mapImage(Medium $medium, MediumAdapterInterface $data): bool
    {
        $hasNoResource = $medium->getResource() === null;
        $resourceHasChanged = $data->getSourceUri() !== $medium->getSourceUri();
        if ($this->download && ($hasNoResource || $resourceHasChanged)) {
            $resource = $this->downloadAsResource($data);
            if ($resource === null) {
                return false;
            }
            $medium->setResource($resource);
        }
        $medium->setSourceUri($data->getSourceUri());

        return true;
    }

    private function downloadAsResource(MediumAdapterInterface $data): ?PersistentResource
    {
        try {
            return $this->resourceManager->importResource($data->getSourceUri());
        } catch (ResourceManagementException $e) {
            $this->logResourceManagementException($data, $e);
            return null;
        }
    }

    private function logResourceManagementException(
        MediumAdapterInterface $data,
        ResourceManagementException $exception
    ): void {
        $message = sprintf(
            'Could not download media element with external id `%s` from `%s`. Ignoring this image.',
            $data->getExternalId(),
            $data->getSourceUri()
        );
        $this->warning($message);
    }
}
