<?php
namespace Newland\Toubiz\Sync\Neos\Domain\Repository;

use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Neos\Flow\Persistence\Doctrine\Repository;
use Neos\Flow\Annotations as Flow;
use Newland\Toubiz\Sync\Neos\Domain\Model\Geometry;

/**
 * @Flow\Scope("singleton")
 */
class GeometryRepository extends Repository
{

    /**
     * @param object $geometry
     * @return void
     */
    public function add($geometry)
    {
        parent::add($geometry);
        $this->persistenceManager->persistAll();
    }

    /**
     * @param string $type
     * @return void
     */
    public function removeByType(string $type)
    {
        $this->_em->createQueryBuilder()
            ->delete($this->_entityName, 'g')
            ->where('g.type = :type')
            ->setParameter('type', $type)
            ->getQuery()
            ->execute();
    }

    /**
     * @param string $type
     * @param float $longitude
     * @param float $latitude
     * @return Geometry|null
     */
    public function findOneContainingCoordinates(string $type, float $longitude, float $latitude)
    {
        $query = $this->whereContains($type, $longitude, $latitude);
        $query->setMaxResults(1);
        return $query->getQuery()->execute()[0] ?? null;
    }

    /**
     * @param string $type
     * @param float $longitude
     * @param float $latitude
     * @return string|null
     */
    public function labelContainingCoordinates(string $type, float $longitude, float $latitude)
    {
        $query = $this->whereContains($type, $longitude, $latitude);
        $query->setMaxResults(1);
        return $query->getQuery()->execute(null, AbstractQuery::HYDRATE_ARRAY)[0]['label'] ?? null;
    }

    /**
     * @param string $type
     * @param float $longitude
     * @param float $latitude
     * @return QueryBuilder
     */
    private function whereContains(string $type, float $longitude, float $latitude): QueryBuilder
    {
        $query = $this->createQueryBuilder('g');
        $query->where('
            g.type = :type AND
            ST_Contains(
                g.geometry,
                ST_GeomFromText(:wkt)
             ) = 1
        ');
        $query->setParameters(
            [
                'wkt' => sprintf('POINT(%f %f)', $longitude, $latitude),
                'type' => $type,
            ]
        );

        return $query;
    }

    public function isEmpty(): bool
    {
        return $this->countAll() === 0;
    }
}
