<?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 Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Persistence\PersistenceManagerInterface;
use Newland\Toubiz\Api\Constants\Language;

/**
 * Abstract importer class.
 *
 * @Flow\Scope("singleton")
 */
abstract class AbstractImporter
{
    /**
     * @Flow\Inject()
     * @var PersistenceManagerInterface
     */
    protected $persistenceManager;

    /**
     * @var mixed
     */
    protected $data;

    /**
     * @var string
     */
    protected $language;

    public function setLanguage(?string $language): void
    {
        if ($language === null) {
            return;
        }

        Language::throwIfInvalid($language);
        $this->language = $language;
    }

    /**
     * Main import method.
     *
     * Must be defined in each implementation.
     *
     * @param mixed $data
     * @return mixed
     */
    abstract public function import($data);

    /**
     * Returns a DateTime instance for given object.
     *
     * @param mixed $object
     * @return \DateTime
     */
    protected function asDateTime($object): \DateTime
    {
        if (is_string($object)) {
            return new \DateTime($object);
        }

        return $object;
    }

    /**
     * Converts date and time strings into a DateTime object.
     *
     * @param string $date A date in YYYY-MM-DD format
     * @param string $time A time in hh:mm:ss format
     * @return \DateTime
     */
    protected function buildDateTimeFromStrings($date, $time = ''): \DateTime
    {
        $object = new \DateTime($date);
        if ($time) {
            [$hour, $minute] = explode(':', $time);
            $object->setTime((int) $hour, (int) $minute);
        }

        return $object;
    }

    protected function updateCollection(Collection $collection, array $data, callable $generator): array
    {
        $generated = [];
        foreach ($data as $row) {
            $value = $generator($row);
            if ($value) {
                $generated[] = $value;
            }
        }

        return $this->setCollectionValues($collection, $generated);
    }

    protected function setCollectionValues(Collection $collection, array $newValues): array
    {
        $new = new ArrayCollection($newValues);
        $removed = [];
        $added = [];

        // Remove old elements
        foreach ($collection as $element) {
            if (!$new->contains($element)) {
                $collection->removeElement($element);
                $removed[] = $element;
            }
        }

        // Add new ones
        foreach ($new as $element) {
            if (!$collection->contains($element)) {
                $collection->add($element);
                $added[] = $element;
            }
        }

        return [ $collection, $added, $removed ];
    }
}
