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

/*
 * 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\ObjectManagement\Exception\InvalidClassException;
use Newland\Toubiz\Api\Service\UuidPredictionServiceInterface;
use Newland\Toubiz\Sync\Neos\Domain\Model\AbstractEntity;
use Newland\Toubiz\Sync\Neos\Domain\Model\Article;
use Newland\Toubiz\Sync\Neos\Domain\Model\Category;
use Newland\Toubiz\Sync\Neos\Exception\InvalidArgumentException;
use Newland\Toubiz\Sync\Neos\Orm\Uuid\CustomUuidGeneration;

class UuidPredictionService implements UuidPredictionServiceInterface
{
    /**
     * @var array
     */
    protected $defaultProperties = [];

    public function setDefaultProperties(array $defaultProperties): void
    {
        $this->defaultProperties = $defaultProperties;
    }

    public function predict(string $type, string $originalId): string
    {
        switch ($type) {
            case 'article':
            case 'articles':
                return $this->predictForEntity(new Article(), $originalId);
            case 'category':
            case 'categories':
                return $this->predictForEntity(new Category(), $originalId);
            default:
                throw new InvalidArgumentException(
                    sprintf('Could not resolve type "%s" to an entity class.', $type),
                    1562157368
                );
        }
    }

    private function predictForEntity(AbstractEntity $entity, string $originalId): string
    {
        if ($entity instanceof CustomUuidGeneration === false) {
            throw new InvalidClassException(sprintf('Class %s is not using deterministic uuids.', get_class($entity)));
        }

        $this->fillProperties($entity);
        $entity->setOriginalId($originalId);

        return $entity->generateUuid()->toString();
    }

    private function fillProperties(AbstractEntity $entity): void
    {
        foreach ($this->defaultProperties as $propertyName => $value) {
            $this->fillProperty($entity, $propertyName, $value);
        }
    }

    private function fillProperty($entity, string $propertyName, $value): void
    {
        $methodName = 'set' . ucfirst($propertyName);
        if (method_exists($entity, $methodName)) {
            $entity->$methodName($value);
        }
    }
}
