<?php

namespace apexl\Io\modules\display\services;

use apexl\Io\includes\HookManager;
use apexl\Io\modules\component\entities\componentEntity;
use apexl\Io\modules\display\Collections\PageRegistry;
use apexl\Io\modules\display\includes\Page;

/**
 * Class Render
 * Provides a global render store for pages.
 * Allows various projects to manipulate the default display output of modules
 * @package apexl\Io\modules\page\services
 */
final class Render
{
    public const string DEFAULT_PAGE_KEY = 'default';
    public final const string HOOK__CONSTRUCT = 'render.construct';
    public final const string HOOK__PRE_BUILD = 'render.build';
    public final const string HOOK__COLLECT_PAGES = 'render.collect_pages';

    private PageRegistry $pages {
        get {
            if (!$this->hasCollectedPages) {
                $this->hookManager->processHook(self::HOOK__COLLECT_PAGES, $this->pages);
                $this->hasCollectedPages = true;
            }

            return $this->pages;
        }
    }
    private bool $hasCollectedPages = false;

    public function __construct(
        protected readonly HookManager $hookManager,
        PageRegistry $pages,
        private string $activePage = self::DEFAULT_PAGE_KEY
    ) {
        $this->pages = $pages;
        $this->hookManager->processHook(self::HOOK__CONSTRUCT, $this);
    }

    public function registerDefault(string $page): void
    {
        $this->registerPage(self::DEFAULT_PAGE_KEY, $page);
    }

    public function registerPage(string $name, Page|string $page): void
    {
        $this->pages->set($name, $page);
    }

    public function content($components, $page = null): Page
    {
        return $this->pages->get($this->pageSetDataEvaluate($page))->addToContent($components);
    }

    private function pageSetDataEvaluate($page): string
    {
        return $page ?? ($this->activePage ?? self::DEFAULT_PAGE_KEY);
    }

    public function setMetaAndPageTitle($title, $page = null): void
    {
        $this->setMetaTitle($title, $page);
        $this->setPageTitle($title, $page);
    }

    public function setMetaTitle($title, $page = null): Page
    {
        return $this->pages->get($this->pageSetDataEvaluate($page))->setMetaTitle($title);
    }

    public function setPageTitle($title, $page = null): Page
    {
        return $this->pages->get($this->pageSetDataEvaluate($page))->setPageTitle($title);
    }

    public function setMetaDescription($desc, $page = null): Page
    {
        return $this->pages->get($this->pageSetDataEvaluate($page))->setMetaDescription($desc);
    }

    /**
     * @param componentEntity[]|componentEntity|null $components
     */
    public function build(array|componentEntity|null $components = null): array
    {
        $this->hookManager->processHook(self::HOOK__PRE_BUILD);
        $page = $this->getPage($this->activePage);

        if (!$page) {
            return [];
        }

        if ($components) {
            if ($components instanceof componentEntity) {
                $components = [$components];
            }
            $page->addToContent($components);
        }

        return $page->getPage();
    }

    public function getPage($name): ?Page
    {
        return $this->pages->get($name) ?? null;
    }

    public function setActive(string $activePage): void
    {
        $this->activePage = $activePage;
    }

    //ensure we take the provided page first, and then fallback until we're on default.

    private function pages(): PageRegistry
    {
        if ($this->pages->isEmpty()) {
            $this->hookManager->processHook(self::HOOK__COLLECT_PAGES, $this->pages);
        }

        return $this->pages;
    }
}
