<?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\Constants\EntityType;
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\Domain\Model\ZipCode;
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 predictForType(string $type, array $properties): string
    {
        switch ($type) {
            case EntityType::ARTICLE:
                return $this->predictForEntity(new Article(), $properties);
            case EntityType::CATEGORY:
                return $this->predictForEntity(new Category(), $properties);
            case 'zipCode':
                return $this->predictForEntity(new ZipCode(), $properties);
            default:
                throw new InvalidArgumentException(
                    sprintf('Could not resolve type "%s" to an entity class.', $type),
                    1562157368
                );
        }
    }

    /**
     * @param CustomUuidGeneration|AbstractEntity $entity
     * @param array $properties
     * @return string
     */
    public function predictForEntity($entity, array $properties): string
    {
        if ($entity instanceof CustomUuidGeneration === false) {
            throw new InvalidClassException(sprintf('Class %s is not using deterministic uuids.', get_class($entity)));
        }

        $this->fillDefaultProperties($entity);
        $this->fillCustomProperties($entity, $properties);

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

    /**
     * @param CustomUuidGeneration|AbstractEntity $entity
     */
    private function fillDefaultProperties($entity): void
    {
        foreach ($this->defaultProperties as $propertyName => $value) {
            $this->fillProperty($entity, $propertyName, $value);
        }
    }

    /**
     * @param CustomUuidGeneration|AbstractEntity $entity
     */
    private function fillCustomProperties($entity, array $properties): void
    {
        foreach ($properties as $propertyName => $value) {
            $this->fillProperty($entity, $propertyName, $value);
        }
    }

    /**
     * @param CustomUuidGeneration|AbstractEntity $entity
     * @param mixed $value
     */
    private function fillProperty($entity, string $propertyName, $value): void
    {
        $methodName = 'set' . ucfirst($propertyName);
        if (method_exists($entity, $methodName)) {
            $entity->$methodName($value);
        }
    }
}
