<?php
/**
 * Created by PhpStorm.
 * User: Admin
 * Date: 02.09.2020
 * Time: 23:55
 */

namespace Diamond\Repositories\Menu;


use Core\Concrete\RequestAwareTrait;
use Core\Contracts\RequestAwareInterface;
use Diamond\Domain\Menu\Contracts\MenuCriteriaInterface;
use Diamond\Domain\Menu\Contracts\MenuEntityInterface;
use Diamond\Domain\Menu\MenuCollection;
use Diamond\Infrastructure\Models\Menu\Menu;
use Diamond\Infrastructure\Models\Menu\MenuQuery;
use Diamond\Repositories\PropelAbstractRepository;
use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\ActiveQuery\ModelCriteria;
use Propel\Runtime\Collection\ObjectCollection;
use Propel\Runtime\Map\TableMap;
use Repo\CollectionInterface;
use Repo\CrudRepositoryBuilderInterface;
use Repo\EntityInterface;
use Repo\PaginationInterface;

class MenuRepository extends PropelAbstractRepository implements CrudRepositoryBuilderInterface,RequestAwareInterface
{
    use RequestAwareTrait;

    public static function createEntity(): EntityInterface
    {
        return new Menu();
    }

    protected function createQuery(): ModelCriteria
    {
        return MenuQuery::create();
    }

    /**
     * @param PaginationInterface|MenuCriteriaInterface $criteria
     * @param ModelCriteria|MenuQuery $dbCriteria
     */
    protected function modifyCriteria(PaginationInterface $criteria, ModelCriteria $dbCriteria): void
    {

        $dbCriteria

            ->_if($criteria->getFilterByParentId() !== null)
            ->filterByParentId($criteria->getFilterByParentId())
            ->_endif()
            ->_if($criteria->getFilterByActive()!==null)
            ->filterByActive($criteria->getFilterByActive()===true?'Y':'N')
            ->_endif()
            ->_if($criteria->getSearchByName())
            ->filterByName($criteria->getSearchByName() . '%', Criteria::LIKE)
            ->_endif()
            ->_if($criteria->getSearchByUrl())
            ->filterByUrl('%' . $criteria->getSearchByUrl() . '%', Criteria::LIKE)
            ->_endif()
            ->_if($criteria->getSearchByTitle())
            ->filterByTitle('%' . $criteria->getSearchByTitle() . '%', Criteria::LIKE)
            ->_endif();
    }

    protected function createCollection(): CollectionInterface
    {
        return new MenuCollection();
    }

    /**
     * @param PaginationInterface|MenuCriteriaInterface $criteria
     * @return CollectionInterface
     * @throws \Repo\Concrete\Exceptions\Collection
     */
    public function findByCriteria(PaginationInterface $criteria): CollectionInterface
    {
        $query = $this->createQuery();
        $this->modifyCriteriaForFilterSort($criteria, $query);
        $this->modifyCriteria($criteria, $query);
        $result = $query->paginate($criteria->getPage(), $criteria->getLimit());

        $collection = self::createCollection();

        $rows = $result->getResults();

        if ($criteria->asTreeView() === true) {
            $this->treeAdaptive($rows, $collection);
        } else {
            foreach ($rows as $row) {
                $collection->push($row);
            }
        }

        return $collection;
    }

    /**
     * @param ObjectCollection $rows
     * @param MenuCollection $collection
     * @throws \Repo\Concrete\Exceptions\Collection
     */
    private function treeAdaptive(ObjectCollection $rows, MenuCollection $collection): void
    {

        $new = [];

        /**
         * @var Menu $row
         * @var Menu $child
         */
        foreach ($rows as $row) {

            if ($row->getParentId() > 0) {
                $new[$row->getParentId()]['childs'][$row->getId()] = $row;
            } else {
                $new[$row->getId()]['model'] = $row;
            }
        }

        foreach ($new as $data) {

            $row = $data['model']??null;

            if (!isset($data['childs']) && $row) {
                $collection->push($row);
                continue;
            }
            if($row){
                $row->setCountChildrens(count($data['childs']));
                $collection->push($row);
            }


            usort($data['childs'],function($el, $el2){
                /**
                 * @var Menu $el
                 * @var Menu $el2
                 */
                return $el->getPosition() > $el2->getPosition() ? 1: -1;
            });


            foreach ($data['childs'] as $child) {
                $collection->push($child);
            }
        }

        //dd($collection);
    }


    /**
     *
     * @return MenuQuery
     */
    public function buildQueryWithDomain(): MenuQuery
    {
        return MenuQuery::create()
            ->useDomainQuery()
            ->filterByDomain(
                sprintf("'%s' REGEXP `domain`", $this->request->getHost()),
                \Propel\Runtime\ActiveQuery\Criteria::CUSTOM
            )
            ->endUse()
            ;
    }
    /**
     * Поиск меню по имени
     * @param string $name
     * @return ObjectCollection
     */
    public function findByName(string $name): ObjectCollection
    {

        return $this->buildQueryWithDomain()
            ->orderByPosition()
            ->orderById()
            ->filterByName($name)
            ->filterByActive('Y')
            ->find()
            ;
    }

    /**
     *
     * @param type $name
     * @return ObjectCollection
     */
    public function findByNameWithOrderParent($name, bool $onlyActive = true): ObjectCollection
    {
        return $this->buildQueryWithDomain()
            ->orderByParentId()
            ->orderByPosition()
            ->filterByName($name)
            ->_if($onlyActive===true)
            ->filterByActive('Y')
            ->_endif()
            ->find();
    }
}