<?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 Newland\Toubiz\Api\ObjectAdapter\AddressAdapterInterface;
use Newland\Toubiz\Api\Service\GeoLocation\GeoLocationServiceInterface;
use Newland\Toubiz\Sync\Neos\Domain\Model\Address;
use Newland\Toubiz\Sync\Neos\Domain\Repository\AddressRepository;
use Newland\Toubiz\Sync\Neos\Service\GeoLocationFactory;

/**
 * Address importer.
 *
 * @Flow\Scope("singleton")
 *
 * @property AddressAdapterInterface $data
 */
class AddressImporter extends AbstractImporter
{
    /**
     * @Flow\Inject
     * @var AddressRepository
     */
    protected $addressRepository;

    /**
     * @var GeoLocationServiceInterface
     */
    protected $geoLocationService;

    public function injectGeoLocationService(GeoLocationFactory $factory)
    {
        $this->geoLocationService = $factory->get('Newland.Toubiz.Sync.Neos.services.GeoLocation');
    }

    /**
     * Import method.
     *
     * Persist given data by creating new objects or updating existing ones.
     *
     * @param AddressAdapterInterface $data
     * @param Address|null $address
     * @return Address
     */
    public function import($data, ?Address $address = null)
    {
        $persisted = $address !== null;
        $address = $address ?? new Address();

        $address->setOriginalId($data->getExternalId());
        $address->setName($data->getTitle());
        $address->setFirstName($data->getFirstName());
        $address->setLastName($data->getLastName());
        $address->setStreet($data->getStreet());
        $address->setZip($this->getZip($address, $data));
        $address->setCity($data->getCity());
        $address->setPhoneNumber($data->getPhoneNumber());
        $address->setEmailAddress($data->getEmailAddress());
        $address->setWebsiteAddress($data->getWebsiteAddress());

        $this->mapCoordinates($address, $data);

        if ($persisted) {
            $this->addressRepository->update($address);
        } else {
            $this->addressRepository->add($address);
        }

        return $address;
    }

    private function mapCoordinates(Address $address, AddressAdapterInterface $data): void
    {
        $latitude = (float) $data->getLatitude();
        $longitude = (float) $data->getLongitude();
        if (abs($latitude) > .1 && abs($longitude) > .1) {
            $address->setLatitude($latitude);
            $address->setLongitude($longitude);
        } else {
            $address->setLatitude(null);
            $address->setLongitude(null);
        }
    }

    private function getZip(Address $address, AddressAdapterInterface $data): ?string
    {
        $zip = $data->getZip();

        // Some addresses have no zip code.
        // Zip codes can then be looked up once if needed.
        if (empty($zip) && empty($address->getZip()) && $data->isLookup()) {
            $zip = $this->geoLocationService->getZipFromGeoLocation(
                $data->getLatitude(),
                $data->getLongitude()
            );
        }

        return $zip;
    }
}
