<?php

namespace Croogo\Extensions\Event;

use Cake\Controller\Controller;
use Cake\Event\Event;
use Cake\Event\EventListenerInterface;
use Cake\Utility\Hash;
use Croogo\Core\Controller\HookableComponentInterface;
use Croogo\Core\Croogo;
use Croogo\Extensions\Exception\ControllerNotHookableException;

/**
 * Class HookableComponentEventHandler
 */
class HookableComponentEventHandler implements EventListenerInterface
{

    /**
     * {@inheritDoc}
     */
    public function implementedEvents()
    {
        return [
            'Controller.beforeInitialize' => 'initialize'
        ];
    }

    /**
     * @param Event $event
     * @return void
     */
    public function initialize(Event $event)
    {
        /* @var \Cake\Controller\Controller|\Croogo\Core\Controller\HookableComponentInterface $controller */
        $controller = $event->getSubject();

        if (!$controller instanceof HookableComponentInterface) {
            throw new ControllerNotHookableException([get_class($controller)]);
        }

        $components = $this->_getComponents($controller);
        foreach ($components as $component => $config) {
            $controller->_loadHookableComponent($component, $config);
        }
    }

    /**
     * Setup the components array
     *
     * @param void
     * @return void
     */
    protected function _setupComponents()
    {
        $components = [];

        $components = Hash::merge(
            $this->_defaultComponents,
            $this->_appComponents
        );

        foreach ($components as $component => $config) {
            if (!is_array($config)) {
                $component = $config;
                $config = [];
            }

            $this->loadComponent($component, $config);
        }
    }

    /**
     * @param $name
     * @param array $config
     *
     * @return mixed
     */
    public function loadComponent($name, array $config = [])
    {
        list(, $prop) = pluginSplit($name);
        list(, $modelProp) = pluginSplit($this->modelClass);
        $component = $this->components()->load($name, $config);
        if ($prop !== $modelProp) {
            $this->{$prop} = $component;
        }

        return $component;
    }

    /**
     * @param Controller $controller
     *
     * @return array
     */
    private function _getComponents(Controller $controller)
    {
        $properties = Croogo::options('Hook.controller_properties', $controller->request);

        $components = [];
        foreach ($properties['_appComponents'] as $component => $config) {
            if (!is_array($config)) {
                $component = $config;
                $config = [];
            }

            $config = Hash::merge([
                'priority' => 10
            ], $config);

            $components[$component] = $config;
        }

        uasort($components, function ($previous, $next) {
            $previousPriority = $previous['priority'];
            $nextPriority = $next['priority'];

            if ($previousPriority === $nextPriority) {
                return 0;
            }

            return ($previousPriority < $nextPriority) ? -1 : 1;
        });

        return $components;
    }
}
