<?php
/**
 * For the full copyright and license information, please view the
 * docs/licenses/LICENSE.txt file that was distributed with this source code.
 */
use PrestaShopBundle\Security\Admin\LegacyAdminTokenValidator;

class CmsControllerCore extends FrontController
{
    public const CMS_CASE_PAGE = 1;
    public const CMS_CASE_CATEGORY = 2;

    /** @var string */
    public $php_self = 'cms';
    public $assignCase;

    /**
     * @var CMS|null
     */
    protected $cms;

    /**
     * @var CMSCategory|null
     */
    protected $cms_category;

    /** @var bool */
    public $ssl = false;

    public function canonicalRedirection(string $canonicalURL = ''): void
    {
        if (Validate::isLoadedObject($this->cms) && ($canonicalURL = $this->context->link->getCMSLink($this->cms, $this->cms->link_rewrite))) {
            parent::canonicalRedirection($canonicalURL);
        } elseif (Validate::isLoadedObject($this->cms_category) && ($canonicalURL = $this->context->link->getCMSCategoryLink($this->cms_category))) {
            parent::canonicalRedirection($canonicalURL);
        }
    }

    /**
     * Initialize cms controller.
     *
     * @see FrontController::init()
     */
    public function init(): void
    {
        if ($id_cms = (int) Tools::getValue('id_cms')) {
            $this->cms = new CMS($id_cms, $this->context->language->id, $this->context->shop->id);
        } elseif ($id_cms_category = (int) Tools::getValue('id_cms_category')) {
            $this->cms_category = new CMSCategory($id_cms_category, $this->context->language->id, $this->context->shop->id);
        }

        if (Configuration::get('PS_SSL_ENABLED') && Tools::getValue('content_only') && $id_cms && Validate::isLoadedObject($this->cms)
            && in_array($id_cms, $this->getSSLCMSPageIds())) {
            $this->ssl = true;
        }

        parent::init();

        $this->canonicalRedirection();

        if (Validate::isLoadedObject($this->cms)) {
            if (!$this->cms->isAssociatedToShop()) {
                $this->redirect_after = '404';
                $this->redirect();
            } elseif (!$this->cms->active) {
                $adminTokenValidator = $this->getContainer()->get(LegacyAdminTokenValidator::class);
                $isAdminTokenValid = $adminTokenValidator->isTokenValid((int) Tools::getValue('id_employee'), Tools::getValue('adtoken'));
                if (!$isAdminTokenValid) {
                    $this->redirect_after = '404';
                    $this->redirect();
                }
            } else {
                $this->assignCase = self::CMS_CASE_PAGE;
            }
        } elseif (Validate::isLoadedObject($this->cms_category) && $this->cms_category->active) {
            $this->assignCase = self::CMS_CASE_CATEGORY;
        } else {
            $this->redirect_after = '404';
            $this->redirect();
        }
    }

    /**
     * Assign template vars related to page content.
     *
     * @see FrontController::initContent()
     */
    public function initContent(): void
    {
        if ($this->assignCase == self::CMS_CASE_PAGE) {
            $cmsVar = $this->objectPresenter->present($this->cms);

            // Chained hook call - if multiple modules are hooked here, they will receive the result of the previous one as a parameter
            $filteredCmsContent = Hook::exec(
                'filterCmsContent',
                ['object' => $cmsVar],
                null,
                false,
                true,
                false,
                null,
                true
            );
            if (!empty($filteredCmsContent['object'])) {
                $cmsVar = $filteredCmsContent['object'];
            }

            $this->context->smarty->assign([
                'cms' => $cmsVar,
            ]);

            if ($this->cms->indexation == 0) {
                $this->context->smarty->assign('nobots', true);
            }

            $this->setTemplate(
                'cms/page',
                ['entity' => 'cms', 'id' => $this->cms->id]
            );
        } elseif ($this->assignCase == self::CMS_CASE_CATEGORY) {
            $cmsCategoryVar = $this->getTemplateVarCategoryCms();

            // Chained hook call - if multiple modules are hooked here, they will receive the result of the previous one as a parameter
            $filteredCmsCategoryContent = Hook::exec(
                'filterCmsCategoryContent',
                ['object' => $cmsCategoryVar],
                null,
                false,
                true,
                false,
                null,
                true
            );
            if (!empty($filteredCmsCategoryContent['object'])) {
                $cmsCategoryVar = $filteredCmsCategoryContent['object'];
            }

            $this->context->smarty->assign($cmsCategoryVar);
            $this->setTemplate(
                'cms/category',
                ['entity' => 'cms_category', 'id' => $this->cms_category->id]
            );
        }
        parent::initContent();
    }

    /**
     * Return an array of IDs of CMS pages, which shouldn't be forwared to their canonical URLs in SSL environment.
     * Required for pages which are shown in iframes.
     */
    protected function getSSLCMSPageIds(): array
    {
        return [(int) Configuration::get('PS_CONDITIONS_CMS_ID'), (int) Configuration::get('LEGAL_CMS_ID_REVOCATION')];
    }

    public function getBreadcrumbLinks(): array
    {
        $breadcrumb = parent::getBreadcrumbLinks();

        if ($this->assignCase == self::CMS_CASE_CATEGORY) {
            $cmsCategory = new CMSCategory($this->cms_category->id_cms_category);
        } else {
            $cmsCategory = new CMSCategory($this->cms->id_cms_category);
        }

        if ($cmsCategory->id_parent != 0) {
            foreach (array_reverse($cmsCategory->getParentsCategories()) as $category) {
                if ($category['active']) {
                    $cmsSubCategory = new CMSCategory($category['id_cms_category']);
                    $breadcrumb['links'][] = [
                        'title' => $cmsSubCategory->getName(),
                        'url' => $this->context->link->getCMSCategoryLink($cmsSubCategory),
                    ];
                }
            }
        }

        if ($this->assignCase == self::CMS_CASE_PAGE && $this->context->controller instanceof CmsControllerCore) {
            $breadcrumb['links'][] = [
                'title' => $this->context->controller->cms->meta_title,
                'url' => $this->context->link->getCMSLink($this->context->controller->cms),
            ];
        }

        return $breadcrumb;
    }

    /**
     * Initializes a set of commonly used variables related to the current page, available for use
     * in the template. @see FrontController::assignGeneralPurposeVariables for more information.
     *
     * @return array
     */
    public function getTemplateVarPage(): array
    {
        $page = parent::getTemplateVarPage();

        if ($this->assignCase == self::CMS_CASE_CATEGORY) {
            $page['body_classes']['cms-id-' . $this->cms_category->id] = true;
        } else {
            $page['body_classes']['cms-id-' . $this->cms->id] = true;
            if (!$this->cms->indexation) {
                $page['meta']['robots'] = 'noindex';
            }
        }

        return $page;
    }

    public function getTemplateVarCategoryCms(): array
    {
        $categoryCms = [];

        $categoryCms['cms_category'] = $this->objectPresenter->present($this->cms_category);
        $categoryCms['sub_categories'] = [];
        $categoryCms['cms_pages'] = [];

        foreach ($this->cms_category->getSubCategories($this->context->language->id) as $subCategory) {
            $categoryCms['sub_categories'][$subCategory['id_cms_category']] = $subCategory;
            $categoryCms['sub_categories'][$subCategory['id_cms_category']]['link'] = $this->context->link->getCMSCategoryLink($subCategory['id_cms_category'], $subCategory['link_rewrite']);
        }

        foreach (CMS::getCMSPages($this->context->language->id, (int) $this->cms_category->id, true, (int) $this->context->shop->id) as $cmsPage) {
            $cmsVar = $this->objectPresenter->present(new CMS((int) $cmsPage['id_cms'], (int) $this->context->language->id));
            $filteredCmsContent = Hook::exec(
                'filterCmsContent',
                ['object' => $cmsVar],
                null,
                false,
                true,
                false,
                null,
                true
            );
            if (!empty($filteredCmsContent['object'])) {
                $cmsVar = $filteredCmsContent['object'];
            }

            $categoryCms['cms_pages'][$cmsPage['id_cms']] = $cmsVar;
            $categoryCms['cms_pages'][$cmsPage['id_cms']]['link'] = $this->context->link->getCMSLink($cmsPage['id_cms'], $cmsPage['link_rewrite']);
        }

        return $categoryCms;
    }

    /**
     * @return CMS|null
     */
    public function getCms(): ?CMS
    {
        return $this->cms;
    }

    /**
     * @return CMSCategory|null
     */
    public function getCmsCategory(): ?CMSCategory
    {
        return $this->cms_category;
    }

    /**
     * {@inheritdoc}
     */
    public function getCanonicalURL(): string
    {
        if (Validate::isLoadedObject($this->cms)) {
            return $this->context->link->getCMSLink($this->cms, $this->cms->link_rewrite);
        } elseif (Validate::isLoadedObject($this->cms_category)) {
            return $this->context->link->getCMSCategoryLink($this->cms_category);
        }

        return '';
    }
}
