<?php
/**
 * Created by PhpStorm.
 * User: Admin
 * Date: 01.09.2020
 * Time: 0:19
 */

namespace Diamond\Repositories;

use Diamond\Domain\Site\Contracts\SiteFilterInterface;
use Propel\Runtime\ActiveQuery\ModelCriteria;
use Propel\Runtime\Connection\ConnectionInterface;
use Repo\CollectionInterface;
use Repo\PaginationInterface;
use Propel\Runtime\Map\TableMap;
use Repo\EntityInterface;

abstract class PropelAbstractRepository
{

    /**
     * @return EntityInterface
     */
    abstract public static function createEntity(): EntityInterface;

    /**
     * @return ModelCriteria
     */
    abstract protected function createQuery(): ModelCriteria;

    abstract protected function createCollection(): CollectionInterface;

    /**
     * @param PaginationInterface $criteria
     * @param ModelCriteria $dbCriteria
     */
    abstract protected function modifyCriteria(PaginationInterface $criteria, ModelCriteria $dbCriteria): void;

    /**
     * @param PaginationInterface|null $criteria
     * @return int
     */
    public function count(?PaginationInterface $criteria): int
    {
        $query = $this->createQuery();
        $this->modifyCriteriaForBaseFilter($criteria, $query);
        $this->modifyCriteria($criteria, $query);

        return $query->count();
    }

    /**
     * @param int $id
     * @return EntityInterface|null
     */
    public function findById(int $id): ?EntityInterface
    {
        return $this->createQuery()->findOneById($id);
    }

    /**
     * создает новую или заполняет
     * @param array $row
     * @param EntityInterface|null $entity
     * @return EntityInterface
     */
    public function buildEntityFromArray(array $row, EntityInterface $entity = null): EntityInterface
    {
        if (!$entity) {
            $entity = static::createEntity();
        }
        $entity->fromArray($row, TableMap::TYPE_CAMELNAME);
        return $entity;
    }

    /**
     * @param EntityInterface|ConnectionInterface $entity
     */
    public function save(EntityInterface $entity): void
    {
        $entity->save();
    }

    /**
     * @param \Repo\EntityInterface $entity
     */
    public function delete(EntityInterface $entity): void
    {
        $entity->delete();
    }

    /**
     * Фильтрация по ID используете при желании в наследнике
     * @param PaginationInterface $criteria
     * @param ModelCriteria $dbCriteria
     * @return void
     */
    public function modifyCriteriaForBaseFilter(PaginationInterface $criteria, ModelCriteria $dbCriteria): void
    {
        $dbCriteria
            ->_if($criteria->getFilterById() !== null)
            ->filterById($criteria->getFilterById())
            ->_endif()
            ->_if($criteria->getFilterByIds() !== null)
            ->filterById($criteria->getFilterByIds())
            ->_endif();
    }

    /**
     * добавляет фильтрацию и сортировку по id а также пагинацию
     * @param PaginationInterface $criteria
     * @param ModelCriteria $dbCriteria
     *
     */
    public function modifyCriteriaForFilterSort(PaginationInterface $criteria, ModelCriteria $dbCriteria): void
    {

        $this->modifyCriteriaForBaseFilter($criteria, $dbCriteria);

        $dbCriteria
            ->_if($criteria->getSortById() !== null)
            ->orderById($criteria->getSortById())
            ->_endif()
        ;
        $dbCriteria
            ->_if($criteria->getLimit() !== null && $criteria->getLimit() > 0)
            ->limit($criteria->getLimit())
            ->_endif()
            ->_if($criteria->getPage() !== null && $criteria->getPage() > 0 && $criteria->getLimit() > 0)
            ->offset(($criteria->getPage() - 1) * $criteria->getLimit())
            ->_endif()
        ;

        if (is_a($criteria, SiteFilterInterface::class) && $criteria->getFilterBySiteId() !== null) {
            $dbCriteria
                ->filterByDomainId($criteria->getFilterBySiteId());
        }
    }

    public function findByCriteria(PaginationInterface $criteria): CollectionInterface
    {

        $query = $this->createQuery();

        $this->modifyCriteriaForFilterSort($criteria, $query);
        $this->modifyCriteria($criteria, $query);
        $collection = $this->createCollection();

        $result = $query->find();

        foreach ($result as $row) {
            $collection->push($row);
        }
        return $collection;

    }
}