<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\ActivityBundle\Repository;

use Chill\ActivityBundle\Entity\Activity;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @method Activity|null find($id, $lockMode = null, $lockVersion = null)
 * @method Activity|null findOneBy(array $criteria, array $orderBy = null)
 * @method Activity[]    findAll()
 * @method Activity[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class ActivityRepository extends ServiceEntityRepository implements AssociatedEntityToStoredObjectInterface
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Activity::class);
    }

    /**
     * @deprecated use @see{ActivityACLAwareRepositoryInterface::findByAccompanyingPeriod}
     *
     * @return Activity[]
     */
    public function findByAccompanyingPeriod(AccompanyingPeriod $period, array $scopes, ?bool $allowNullScope = false, ?int $limit = 100, ?int $offset = 0, array $orderBy = ['date' => 'desc']): array
    {
        $qb = $this->createQueryBuilder('a');
        $qb->select('a');

        if (!$allowNullScope) {
            $qb
                ->where($qb->expr()->in('a.scope', ':scopes'))
                ->setParameter('scopes', $scopes);
        } else {
            $qb
                ->where(
                    $qb->expr()->orX(
                        $qb->expr()->in('a.scope', ':scopes'),
                        $qb->expr()->isNull('a.scope')
                    )
                )
                ->setParameter('scopes', $scopes);
        }

        $qb
            ->andWhere(
                $qb->expr()->eq('a.accompanyingPeriod', ':period')
            )
            ->setParameter('period', $period);

        foreach ($orderBy as $k => $dir) {
            $qb->addOrderBy('a.'.$k, $dir);
        }

        $qb->setMaxResults($limit)->setFirstResult($offset);

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

    /**
     * @return Activity[]
     */
    public function findByPersonImplied(Person $person, array $scopes, ?array $orderBy = ['date' => 'DESC'], ?int $limit = 100, ?int $offset = 0): array
    {
        $qb = $this->createQueryBuilder('a');
        $qb->select('a');

        $qb
            ->where($qb->expr()->in('a.scope', ':scopes'))
            ->setParameter('scopes', $scopes)
            ->andWhere(
                $qb->expr()->orX(
                    $qb->expr()->eq('a.person', ':person'),
                    ':person MEMBER OF a.persons'
                )
            )
            ->setParameter('person', $person);

        foreach ($orderBy as $k => $dir) {
            $qb->addOrderBy('a.'.$k, $dir);
        }

        $qb->setMaxResults($limit)->setFirstResult($offset);

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

    public function findAssociatedEntityToStoredObject(StoredObject $storedObject): ?Activity
    {
        $qb = $this->createQueryBuilder('a');
        $query = $qb
            ->leftJoin('a.documents', 'ad')
            ->where('ad.id = :storedObjectId')
            ->setParameter('storedObjectId', $storedObject->getId())
            ->getQuery();

        return $query->getOneOrNullResult();
    }
}
