<?php

namespace Velis\Mvc\Module;

use Application\Demo\UserProvider;
use Phalcon\Di\FactoryDefault;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\ModuleDefinitionInterface;
use Velis\Acl\Role;
use Velis\App;
use Velis\App\PhalconVersion;
use Velis\Filter;
use Velis\Lang;
use Velis\Mvc\Annotation;
use Velis\Mvc\View;

/**
 * Base MVC module
 * @author Olek Procki <olo@velis.pl>
 */
abstract class BaseModule implements ModuleDefinitionInterface
{
    /**
     * Module name
     */
    protected string $_module;

    /**
     * Constructor
     */
    public function __construct()
    {
        $class = explode('\\', get_class($this));
        array_pop($class);

        $this->_module = end($class);
    }

    /**
     * Registers module specific autoloaders
     */
    public function registerAutoloaders($di = null)
    {
    }

    /**
     * Registers the core services
     * @param FactoryDefault $di
     */
    public function registerServices($di)
    {
        $this
            ->registerDispatcher($di)
            ->registerView($di)
        ;
    }

    /**
     * Registers module specific services
     * @param FactoryDefault $di
     */
    public function registerCommonServices($di)
    {
    }

    /**
     * Registers the dispatcher
     *
     * @param FactoryDefault $di
     * @return BaseModule
     */
    protected function registerDispatcher($di)
    {
        $moduleName = $this->_module;

        $di->set('dispatcher', function () use ($moduleName) {
            $dispatcher = new Dispatcher();

            //Attach a event listener to the dispatcher
            $eventManager = new EventsManager();
            $eventManager->attach('dispatch', new Annotation());
            $dispatcher->setEventsManager($eventManager);
            $dispatcher->setDefaultNamespace($moduleName . "\Controller\\");
            return $dispatcher;
        });

        return $this;
    }


    /**
     * Registering the view component
     *
     * @param FactoryDefault $di
     * @return $this
     */
    protected function registerView($di)
    {
        $moduleName = $this->_module;

        $di->set('view', function () use ($di, $moduleName) {
            $view = new View();

            $layoutPath = MODULE_PATH . 'Application/view/layout/';
            $view->setLayoutsDir($layoutPath);

            $template = App::$config->layout->template ?: 'layout';
            if ($di['request'] && $di['request']->getHeader('X_INSTANT_REQUEST')) {
                $template .= '-instant';
            }
            $view->setLayout($template);

            /** @var View\Engine\EngineFactory $factory */
            $factory = $di->get('templatingEngineFactory');

            $smartyRenderer = $factory->createEngine($view);
            $view->setSmartyEngine($smartyRenderer);

            $view->registerEngines([
                '.tpl' => $smartyRenderer,
            ]);

            $view->setViewsDir(
                MODULE_PATH . $moduleName . '/view/' . strtolower(Filter::filterToDash($moduleName))
            );

            $revNo = getenv('JS_REVISION_NO') ?: App::$config->js->revisionNo;
            $view->_flash = App::$di['flash'];
            $view->_filter = App::$registry['filter'];
            $view->_LANG = new Lang();
            $view->revisionNo = $revNo ?? '';

            $version = new PhalconVersion();
            $view->_phalconVersion = $version->getVersionString();

            if (App::demoMode() && App::$user->isLogged()) {
                /** @var UserProvider $userProvider */
                $userProvider = $di->get('application.demo.userProvider');
                try {
                    $users = $userProvider->getDemoLoginUsers();
                } catch (\Exception $e) {
                    $users = [];
                }

                $view->_demoLoginUsers = $users;
                $view->_roles = Role::listCached();
            }

            return $view;
        });

        return $this;
    }
}
