<?php

namespace App\Repository\Tools;

use App\Entity\User;
use App\Entity\Group;
use App\Entity\Directory;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;

class DocumentRepositoriesExtension extends ServiceEntityRepository
{
    public array $fields = [];
    private QueryBuilder $qb;
    private ?QueryBuilder $qbsearch = null;
    private ?Group $group = null;
    private ?User $user = null;

    /**
     * @param string $entityClass The class name of the entity this repository manages
     * @psalm-param class-string<T> $entityClass
     */
    public function __construct(ManagerRegistry $registry, string $entityClass = null)
    {
        parent::__construct($registry, $entityClass);
    }

    /**
     * Equivalent of FindAll()
     *     *
     * @return QueryBuilder
     */
    public function getQueryBuilder()
    {
        return $this->createQueryBuilder("d");
        ;
    }

    /**
     * Allow listing of documents wich are allowed for a given group
     *
     * @param Group $Group
     * @return QueryBuilder
     */
    public function getGroupQuery(Group $Group)
    {
        return $this->getQueryBuilder()
            ->where(':group MEMBER OF d.allowedGroups')
            ->setParameter('group', $Group)
        ;
    }

    public function listForUser(User $User, bool $ignoreGroup = false)
    {
        $this->user = $User;
        $this->group = $User->getMainGroup();
        $this->qbsearch = null;
        $this->qb = ($User->getAdminMode() || $ignoreGroup) ? $this->getQueryBuilder()
                                                            : $this->getGroupQuery($this->group);





        if (!$User->hasPermission('group_ignore_subgroups')) {
            $this->qb->andWhere('d.allowedSubGroups is empty');
            foreach ($User->getSubGroups() as $key => $subG) {
                $this->qb->orWhere(':group' . $key . ' MEMBER OF d.allowedSubGroups')
                ->setParameter(':group' . $key, $subG);
            }
        }

        if (!$User->getAdminMode()) {
            if (!$User->hasPermission('general_legal_view')) {
                $this->qb->andWhere('d.needLegalAccess = 0');
            }
            if (!$User->hasPermission('general_medical_view')) {
                $this->qb->andWhere('d.needMedicalAccess = 0');
            }

            if (!$User->hasPermission('group_administrate')) {
                $this->qb->andWhere('d.needGroupAdministration = 0');
            }
        }

        return $this;
    }

    public function list()
    {
        $this->qbsearch = null;
        $this->qb = $this->getQueryBuilder();
        return $this;
    }

    public function getResult()
    {
        if (null !== $this->qbsearch) {
            $this->qbsearch->andWhere($this->qb->expr()->in('s.id', $this->qb->getDQL()));
            if (null !== $this->user && !$this->user->getAdminMode()) {
                $this->qbsearch->setParameter('group', $this->group);
            }
            return $this->qbsearch->getQuery()->getResult();
        }

        return $this->qb->getQuery()->getResult();
    }

    public function limit(int $limit)
    {
        $this->qb->setMaxResults($limit);
        return $this;
    }

    public function limitType(string $type)
    {
        $this->qb->andWhere($this->qb->expr()->isInstanceOf('d', 'App\Entity\\' . ucfirst($type)));
        return $this;
    }

    public function archive(bool $archive = true)
    {
        if (true === $archive) {
            $this->qb->andWhere('d.archive = 1');
        } else {
            $this->qb->andWhere('d.archive = 0');
        }
        return $this;
    }

    public function limitDirectory(?Directory $directory)
    {
        if (null === $directory) {
            return $this;
        }

        $this->qb->andWhere('d.directory = ' . $directory->getId());
        return $this;
    }

    public function limitGroup(?Group $group)
    {
        if (null === $group) {
            return $this;
        }

        $this->qb->andWhere('d.mainGroup = ' . $group->getId());
        return $this;
    }

    public function order(array $order)
    {
        foreach ($order as $key => $value) {
            if ($key === array_key_first($order)) {
                $this->qb->orderBy('d.' . $key, $value);
            } else {
                $this->qb->addorderBy('d.' . $key, $value);
            }
        }
        return $this;
    }

    public function search(?string $search)
    {
        if (null === $search) {
            return $this;
        }

        if (null === $this->qbsearch) {
            $this->qbsearch = $this ->createQueryBuilder("s")->where('s.title LIKE :searchkey');
            $this->qbsearch->orWhere('s.id LIKE :searchkey');
            $searchTime = str_replace('/', '-', $search);
            if (($timestamp = strtotime($searchTime)) != false) {
                $this->qbsearch->where('s.createdAt LIKE :searchkeydate')
                ->setParameter('searchkeydate', '%' . date('Y-m-d', $timestamp) . '%');
            }
        }

        foreach ($this->fields as $key => $value) {
            $this->qbsearch->orWhere('s.' . $value . ' LIKE :searchkey');
        }

        $this->qbsearch ->leftjoin('s.mainGroup', 'mg')
                        ->orWhere('mg.shortName LIKE :searchkey')
                        ->orWhere('mg.name LIKE :searchkey')
                        ;
        $this->qbsearch ->leftjoin('s.creator', 'cr')
                        ->orWhere('cr.firstname LIKE :searchkey')
                        ->orWhere('cr.lastname LIKE :searchkey')
                        ;

        $this->qbsearch->setParameter('searchkey', '%' . $search . '%');

        return $this;
    }
}
