<?php

/**
 * Lifestyle Webconsulting GmbH
 *
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is private by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * @copyright  2018 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace LifeStyle\ActivityLogBundle\EventListener;

use Doctrine\Common\Annotations\Reader;
use Doctrine\Common\Util\ClassUtils;
use LifeStyle\ActivityLogBundle\ActivityLogHandlerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use LifeStyle\ActivityLogBundle\Annotation\ActivityLog;

/**
 * Class ControllerAnnotationListener
 *
 * @copyright  2018 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 * @package    LifeStyle\ActivityLogBundle\EventListener
 */
class ControllerAnnotationListener
{
    /**
     * @var Reader
     */
    private $reader;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var ActivityLogHandlerInterface
     */
    private $activityLogHandler;

    /**
     * ControllerAnnotationListener constructor.
     * @param Reader $reader
     * @param LoggerInterface $logger
     * @param ActivityLogHandlerInterface $activityLogHandler
     */
    public function __construct(
        Reader $reader,
        LoggerInterface $logger,
        ActivityLogHandlerInterface $activityLogHandler
    ) {
        $this->reader = $reader;
        $this->logger = $logger;
        $this->activityLogHandler = $activityLogHandler;
    }

    /**
     * @param FilterControllerEvent $event
     */
    public function onKernelController(FilterControllerEvent $event)
    {
        if (!$event->isMasterRequest()) {
            // Don't do anything if it's not the master request
            return;
        }

        $controller = $event->getController();
        if (!is_array($controller)) {
            // There should be no annotation for a closure
            return;
        }

        list($controllerObject, $methodName) = $controller;

        /** @var ActivityLog|null $controllerAnnotation */
        $controllerAnnotation = $this->reader->getClassAnnotation(
                new \ReflectionClass(ClassUtils::getClass($controllerObject)),
                ActivityLog::class
        );
        if (null !== $controllerAnnotation) {
            // All actions in controller should be logged
            $this->logActivity(get_class($controllerObject), $methodName, $controllerAnnotation->getType());
            return;
        }

        $reflectionObject = new \ReflectionObject($controllerObject);
        $reflectionMethod = $reflectionObject->getMethod($methodName);

        /** @var ActivityLog|null $methodAnnotation */
        $methodAnnotation = $this->reader->getMethodAnnotation($reflectionMethod, ActivityLog::class);
        if (null !== $methodAnnotation) {
            // Log this controller action only
            $this->logActivity(get_class($controllerObject), $methodName, $methodAnnotation->getType());
        }
    }

    /**
     * @param string $controllerName
     * @param string $actionName
     * @param string $logType
     */
    private function logActivity($controllerName, $actionName, $logType)
    {
        $this->logger->info(sprintf(
            'ActivityLog Controller Annotation: %s::%s %s',
            $controllerName,
            $actionName,
            $logType
        ));

        $this->activityLogHandler->log($controllerName, $actionName, $logType);
    }
}
