<?php

namespace apexl\Io\modules\display\includes;

use apexl\ClassEngine\EngineSingleton;
use apexl\Config\Singleton;
use apexl\Io\includes\Hook;
use apexl\Io\modules\component\entities\componentEntity;
use apexl\Io\modules\display\regions\ContentRegion;
use apexl\Io\modules\display\regions\PageContentRegion;
use apexl\Io\modules\menu\services\Menu;
use apexl\Io\modules\user\entities\userEntity;
use apexl\Io\modules\user\services\currentUser;
use apexl\Io\services\pathUtility;

abstract class Page extends EngineSingleton
{
    protected $metadata;
    protected $config;
    protected $components = [];

    /** @var Menu  */
    protected $menu;
    /** @var userEntity */
    protected $currentUser;
    protected $path;
    protected $TitleTile;

    public $pageTitle;

    /** @var region - While the page has its own "components" array, we're working in regions so need a holder. */
    protected $globalRegion;

    protected function __construct()
    {
        parent::__construct();
        $this->metadata = (object)[];
        $this->config = Singleton::getInstance();
        $this->currentUser = currentUser::getCurrentUser();
        $this->menu = Menu::getInstance();
        $this->path = pathUtility::getInstance();

        //do this in a method so extending classes can override.
        $route = $this->menu->getMenuItem($this->path->getCurrentRouteName());
        $this->setPageTitle($route->title ?? $this->path->getCurrentRouteName());
        $this->buildRegions();
    }

    /**
     * @param $title
     * @return $this
     */
    public function setPageTitle($title)
    {
        $this->pageTitle = $title;
        if ($this->TitleTile && method_exists($this->TitleTile, 'text')) {
            $this->TitleTile->text($this->pageTitle);
        }
        return $this;
    }

    public function setMetaTitle($title)
    {
        $this->metadata->title = $title;
        return $this;
    }

    public function setMetaDescription($desc)
    {
        $this->metadata->description = $desc;
        return $this;
    }

    public function setMetadata($metaKey, $metaValue)
    {
        $this->metadata->$metaKey = $metaValue;
        return $this;
    }

    public function addComponent(componentEntity $component, $registerName = null)
    {
        if ($registerName) {
            $this->{$registerName} = $component;
        } else {
            $this->{$component->getName()} = $component;
        }
        $this->components[] = $component;
        return $this;
    }

    public function registerTitleComponent($component)
    {
        $this->TitleTile = $component;
    }

    public function getPageTitle()
    {
        return $this->getPageTitle();
    }

    /**
     * Get the top level component by name.
     * @TODO change how components are registered maybe?
     * @param $name
     * @return componentEntity|bool
     */
    public function getComponent($name)
    {
        $noComponents = count($this->components);
        for ($i=0;$i<$noComponents;++$i) {
            if ($this->components[$i]->name == $name) {
                return $this->components[$i];
            }
        }
        return false;
    }

    /**
     * Allow top level components to be replaced
     * @param $name
     * @param componentEntity $component
     * @return bool
     */
    public function replaceComponent($name, componentEntity $component)
    {
        $noComponents = count($this->components);
        $replaced = false;
        for ($i=0;$i<$noComponents;++$i) {
            if ($this->components[$i]->name == $name) {
                $this->components[$i] = $component;
                $replaced = true;
            }
        }
        return $replaced;
    }

    /**
     * @param $component
     * @param $regionName
     * @param $weight
     * @return $this
     */
    protected function addToRegion($component, $regionName, $weight)
    {
        if (is_array($component)) {
            foreach ($component as $comp) {
                if (!empty($comp)) {
                    $this->globalRegion->addComponent($comp, $regionName, $weight);
                }
            }
        } else {
            $this->globalRegion->addComponent($component, $regionName, $weight);
        }
        return $this;
    }

    /**
     * Default must have content!
     */
    protected function buildRegions()
    {
        $this->globalRegion = new PageContentRegion();
        $this->globalRegion->addRegions([new ContentRegion()]);
    }

    /**
     * @param $component
     * @param null $weight
     */
    public function addToContent($component, $weight = null)
    {
        $this->addToRegion($component, ContentRegion::class, $weight);
        return $this;
    }

    /**
     * Get the page as an MD array
     * @return array
     */
    public function getPage()
    {
        $this->addComponent($this->globalRegion->buildRegions());
        $this->setMetaTitle($this->pageTitle.' | '.($this->config->app->defaultMetaTitle ?? "Io Dashboard"));
        $data = [];
        $data['metadata'] = $this->metadata;
        foreach ($this->components as $component) {
            //we need to decode the cast components as they will be json encoded.
            //We do this to ensure we have all nested data.
            $data['components'][] = json_decode((string) $component);
        }
        return $data;
    }

    /**
     * Build and output the page
     * @return false|string
     */
    public function __toString()
    {
        return json_encode($this->getPage());
    }
}
