<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\PageBuilder\Repository;

use CpCreation\VitiCore\PageBuilder\Model\Page;
use CpCreation\VitiCore\Repository\BaseRepository;
use Doctrine\Persistence\ManagerRegistry;

final class PageRepository extends BaseRepository
{
    /**
     * @throws \ReflectionException
     */
    public function __construct(private readonly ManagerRegistry $registry)
    {
        parent::__construct($this->registry, Page::class);
    }

    public function findOneByCode(string $code): ?Page
    {
        $page = $this->createQueryBuilder('p')
            ->andWhere('p.code = :code')
            ->setParameter('code', trim($code))
            ->setMaxResults(1)
            ->getQuery();

        /** @var Page|null $result */
        $result = $page->getOneOrNullResult();

        return $result;
    }

    public function findOneSystemByRouteName(string $routeName): ?Page
    {
        $routeName = trim($routeName);

        $query = $this->createQueryBuilder('p')
            ->leftJoin('p.translations', 't')
            ->addSelect('t')
            ->andWhere('p.routeMode = :routeMode')
            ->andWhere('p.routeName = :routeName')
            ->setParameter('routeMode', Page::ROUTE_MODE_SYSTEM)
            ->setParameter('routeName', $routeName)
            ->setMaxResults(1)
            ->getQuery();

        /** @var Page|null $result */
        $result = $query->getOneOrNullResult();

        return $result;
    }

    /**
     * @return Page[]
     */
    public function findForAdmin(): array
    {
        return $this->createQueryBuilder('p')
            ->leftJoin('p.translations', 't')
            ->addSelect('t')
            ->orderBy('p.createdAt', 'DESC')
            ->addOrderBy('p.name', 'ASC')
            ->getQuery()
            ->getResult();
    }

    public function hasConflictingPath(Page $page, string $locale, string $path): bool
    {
        $path = trim($path, '/');

        $query = $this->createQueryBuilder('p')
            ->select('COUNT(p.id)')
            ->innerJoin('p.translations', 't')
            ->andWhere('t.locale = :locale')
            ->andWhere('t.path = :path')
            ->andWhere('p.id != :pageId')
            ->setParameter('locale', $locale)
            ->setParameter('path', $path)
            ->setParameter('pageId', $page->getId())
            ->getQuery();

        return (int) $query->getSingleScalarResult() > 0;
    }

    public function findOnePublishedCmsByPath(string $path, string $locale, ?\DateTimeInterface $referenceDate = null): ?Page
    {
        $referenceDate ??= new \DateTimeImmutable();
        $path = trim($path, '/');

        $query = $this->createQueryBuilder('p')
            ->innerJoin('p.translations', 't')
            ->addSelect('t')
            ->andWhere('p.routeMode = :routeMode')
            ->andWhere('p.disabled = FALSE')
            ->andWhere('(p.publishedAt <= :datetime OR p.publishedAt IS NULL)')
            ->andWhere('(p.unPublishedAt >= :datetime OR p.unPublishedAt IS NULL)')
            ->andWhere('t.locale = :locale')
            ->andWhere('t.path = :path')
            ->setParameter('routeMode', Page::ROUTE_MODE_CMS)
            ->setParameter('datetime', $referenceDate)
            ->setParameter('locale', $locale)
            ->setParameter('path', $path)
            ->setMaxResults(1)
            ->getQuery();

        /** @var Page|null $result */
        $result = $query->getOneOrNullResult();

        return $result;
    }

    public function findOneCmsByPathForAdmin(string $path, string $locale): ?Page
    {
        $path = trim($path, '/');

        $query = $this->createQueryBuilder('p')
            ->innerJoin('p.translations', 't')
            ->addSelect('t')
            ->andWhere('p.routeMode = :routeMode')
            ->andWhere('t.locale = :locale')
            ->andWhere('t.path = :path')
            ->setParameter('routeMode', Page::ROUTE_MODE_CMS)
            ->setParameter('locale', $locale)
            ->setParameter('path', $path)
            ->setMaxResults(1)
            ->getQuery();

        /** @var Page|null $result */
        $result = $query->getOneOrNullResult();

        return $result;
    }
}
