<?php

/*
 * This file is part of the EasyWeChatComposer.
 *
 * (c) 张铭阳 <mingyoungcheung@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */
namespace EasyWeChatComposer;

use EasyWeChat\Kernel\Contracts\EventHandlerInterface;
use Pimple\Container;
use ReflectionClass;
class Extension
{
    /**
     * @var \Pimple\Container
     */
    protected $app;
    /**
     * @var string
     */
    protected $manifestPath;
    /**
     * @var array|null
     */
    protected $manifest;
    /**
     * @param \Pimple\Container $app
     */
    public function __construct(Container $app)
    {
        $this->app = $app;
        $this->manifestPath = __DIR__ . '/../extensions.php';
    }
    /**
     * Get observers.
     *
     * @return array
     */
    public function observers()
    {
        if ($this->shouldIgnore()) {
            return [];
        }
        $observers = [];
        foreach ($this->getManifest() as $name => $extra) {
            $observers = array_merge($observers, isset($extra['observers']) ? $extra['observers'] : []);
        }
        return array_map([$this, 'listObserver'], array_filter($observers, [$this, 'validateObserver']));
    }
    /**
     * @param mixed $observer
     *
     * @return bool
     */
    protected function isDisable($observer)
    {
        return in_array($observer, $this->app->config->get('disable_observers', []));
    }
    /**
     * Get the observers should be ignore.
     *
     * @return bool
     */
    protected function shouldIgnore()
    {
        return !file_exists($this->manifestPath) || $this->isDisable('*');
    }
    /**
     * Validate the given observer.
     *
     * @param mixed $observer
     *
     * @return bool
     *
     * @throws \ReflectionException
     */
    protected function validateObserver($observer)
    {
        return !$this->isDisable($observer) && (new ReflectionClass($observer))->implementsInterface(EventHandlerInterface::class) && $this->accessible($observer);
    }
    /**
     * Determine whether the given observer is accessible.
     *
     * @param string $observer
     *
     * @return bool
     */
    protected function accessible($observer)
    {
        if (!method_exists($observer, 'getAccessor')) {
            return true;
        }
        return in_array(get_class($this->app), (array) $observer::getAccessor());
    }
    /**
     * @param mixed $observer
     *
     * @return array
     */
    protected function listObserver($observer)
    {
        $condition = method_exists($observer, 'onCondition') ? $observer::onCondition() : '*';
        return [$observer, $condition];
    }
    /**
     * Get the easywechat manifest.
     *
     * @return array
     */
    protected function getManifest()
    {
        if (!is_null($this->manifest)) {
            return $this->manifest;
        }
        return $this->manifest = file_exists($this->manifestPath) ? require $this->manifestPath : [];
    }
}