<?php

namespace Opentalent\OtCore\Website;

use FluidTYPO3\Vhs\Service\PageService;
use Opentalent\OtCore\Exception\NoSiteSelected;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Domain\Repository\PageRepository;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
 * Class OtPageRepository
 *
 * Provides some useful methods to query typo3 pages
 *
 * @package Opentalent\OtCore\Page
 */
class OtPageRepository
{
    /**
     * @var PageService
     */
    private PageService $pageService;

    public function injectPageService(PageService $pageService)
    {
        $this->pageService = $pageService;
    }

    /**
     * @var PageRepository
     */
    private PageRepository $pageRepository;

    public function injectPageRepository(PageRepository $pageRepository)
    {
        $this->pageRepository = $pageRepository;
    }

    /**
     * @var ConnectionPool
     */
    private ConnectionPool $connectionPool;

    public function injectConnectionPool(ConnectionPool $connectionPool)
    {
        $this->connectionPool = $connectionPool;
    }

    /**
     * Returns all the subpages of the given page
     *
     * @param int $pid The uid of the parent page
     * @param bool $withRestrictions Set to true to add the standard restrictions (deleted, forbidden...etc.)
     * @return array
     */
    public function getPagesByPid(int $pid, bool $withRestrictions=false): array
    {
        $queryBuilder = $this->connectionPool->getQueryBuilderForTable('pages');
        if (!$withRestrictions) {
            $queryBuilder->getRestrictions()->removeAll();
        }
        return $queryBuilder
            ->select('*')
            ->from('pages')
            ->where($queryBuilder->expr()->eq('pid', $pid))
            ->execute()
            ->fetchAll();
    }

    /**
     * Returns the root page of the given page website,
     * or the page itself if the given page is
     * already the rootpage of the site
     *
     * @param $pageUid
     *
     * @return array
     */
    public function getRootPageFor($pageUid): array
    {
        $page = $this->getPage($pageUid);

        while ($page && $page['is_siteroot'] !== 1) {
            $page = $this->getPage($page['pid']);
        }
        return $page;
    }

    /**
     * Recursively returns all the subpages of the given page
     *
     * @param int $pageUid The uid of the parent page
     * @param bool $withRestrictions Set to true to add the standard restrictions (deleted, forbidden...etc.)
     * @return array
     */
    public function getAllSubpagesForPage(int $pageUid, bool $withRestrictions=false): array
    {
        $subpages = [];

        $stack = $this->getPagesByPid($pageUid, $withRestrictions);

        foreach ($stack as $page) {
            $subpages[] = $page;
            $children = $this->getAllSubpagesForPage($page['uid']);
            if (!empty($children)) {
                $subpages = array_merge($subpages, $children);
            }
        }
        return $subpages;
    }

    /**
     * Returns all the pages of the given page's website, starting from the root page
     *
     * @param int $pageUid
     * @param bool $withRestrictions Set to true to add the standard restrictions (deleted, forbidden...etc.)
     * @return array
     */
    public function getPageWithSubpages(int $pageUid, bool $withRestrictions=false): array
    {
        return array_merge([$this->getPage($pageUid)], $this->getAllSubpagesForPage($pageUid, $withRestrictions));
    }

    /**
     * [Backend Only]
     * Returns the page currently selected in the backend if any
     *
     * @return int|null
     */
    public function getCurrentBePageId(): ?int
    {
        return (int)GeneralUtility::_GP('id');
    }

    /**
     * [Backend Only]
     * Return the root uid of the currently selected website if any,
     * or throw a NoSiteSelected exception
     *
     * @return int
     * @throws NoSiteSelected
     */
    public function getCurrentBeRootUid(): int
    {
        $pageUid = $this->getCurrentBePageId();

        $rootPage = $this->getRootPageFor($pageUid);
        $rootUid = $rootPage['uid'] ?? 0;
        if (!($rootUid > 0)) {
            throw new NoSiteSelected();
        }
        return $rootUid;
    }

    /**
     * [Backend Only]
     *
     * Return the mountpoint(s) for the current BE User
     */
    public function getCurrentBeUserMountpoints(): array
    {
        // Check if the current be-user has a db_mountpoint, and only has one.
        // If so, this will be considered as the selected site (since its the only one available)
        $be_user = $GLOBALS['BE_USER'];
        if ($be_user == null) {
            return [];
        }

        $mountpoints = $be_user->returnWebmounts();
        return array_filter($mountpoints, function($m) { return is_numeric($m) && (int)$m > 0; });
    }

    public function getPage(int $uid): array
    {
        return $this->pageRepository->getPage_noCheck($uid);
    }
}
