<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonPickwareCommon\Classes\Subscribers;

use Doctrine\Common\Collections\ArrayCollection;
use Shopware\Plugins\ViisonCommon\Classes\Subscribers\Base;
use Shopware\Plugins\ViisonPickwareCommon\Components\ApiRequestCompatibilityManager;

/**
 * @deprecated 6.0.0 Use the following classes instead:
 *     - `\Shopware\Plugins\ViisonPickwareERP\Components\RestApi\RequestLogging\AbstractRestApiRequestsLogFilterSubscriber`
 *     - `\Shopware\Plugins\ViisonPickwareERP\Components\RestApi\Routing\AbstractRestApiRouterSubscriber`
 *     - `\Shopware\Plugins\ViisonPickwareCommon\Classes\Subscribers\RestApiRequestCompatibilityLayerSubscriber`
 */
// phpcs:ignore VIISON.Classes.AbstractClassName -- cannot change name to keep backwards compatiblity
abstract class PickwareApiRequests extends Base
{
    /**
     * @var string $compatibilityLayerRootPath
     */
    private $compatibilityLayerRootPath;

    /**
     * @var string $compatibilityLayerBaseNamespace
     */
    private $compatibilityLayerBaseNamespace;

    /**
     * @param \Shopware_Components_Plugin_Bootstrap $pluginBootstrap
     * @param string $compatibilityLayerRootPath (optional)
     * @param string $compatibilityLayerBaseNamespace (optional)
     */
    public function __construct(\Shopware_Components_Plugin_Bootstrap $pluginBootstrap, $compatibilityLayerRootPath = null, $compatibilityLayerBaseNamespace = null)
    {
        parent::__construct($pluginBootstrap);

        $this->compatibilityLayerRootPath = $compatibilityLayerRootPath;
        $this->compatibilityLayerBaseNamespace = $compatibilityLayerBaseNamespace;
    }

    /**
     * @see \Shopware\Plugins\ViisonCommon\Classes\Subscribers\Base::getSubscribedEvents()
     */
    public static function getSubscribedEvents()
    {
        return [
            ApiRequestCompatibilityManager::EVENT_COLLECT_API_REQUEST_COMPATIBILITY_LAYERS => 'onCollectAPIRequestCompatibilityLayers',
            'Shopware_Plugins_ViisonPickwareCommon_ApiRequestLogger_FilterLoggedResponseJson' => 'onFilterLoggedResponseJson',
            'Shopware_Plugins_ViisonPickwareCommon_ApiRequestLogger_ShouldLogRequest' => 'onShouldLogRequest',
            'Shopware_Plugins_ViisonPickware_APIControllerRouting' => 'onApiControllerRouting',
        ];
    }

    /**
     * Filters specific fields from the given $responseJson and returns the filtered data.
     *
     * Note: This method is not abstract, which makes this calls backwards compatible.
     *
     * @param array $responseJson
     * @param \Enlight_Controller_Request_Request $request
     * @return array
     */
    public function filterLoggedResponseJson(array $responseJson, \Enlight_Controller_Request_Request $request)
    {
        // Don't filter anything by default
    }

    /**
     * Determines and returns whether to log the given request in the Pickware API log or not.
     *
     * Note: This method is not abstract, which makes this calls backwards compatible.
     *
     * @param \Enlight_Controller_Request_Request $request
     * @return boolean
     */
    public function shouldLogRequest(\Enlight_Controller_Request_Request $request)
    {
        // Don't return anything by default
    }

    /**
     * Applies custom routing for the given request. That is, if the request should be routed to
     * a custom API controller, the name of that controller must be returned. Otherwise NULL must
     * be returned to indicate that no custom routing is required.
     *
     * @param \Enlight_Controller_Request_Request $request
     * @return string|null
     */
    abstract public function applyCustomRouting(\Enlight_Controller_Request_Request $request);

    /**
     * Iterates all files contained in the layer directory path and parses their names to find
     * all compatibility layers, which can be applied to the requested controller with the given
     * name and whose version is greater or equal the required API version.
     *
     * @param \Enlight_Event_EventArgs $args
     * @return \Doctrine\Common\Collections\ArrayCollection|null
     */
    public function onCollectAPIRequestCompatibilityLayers(\Enlight_Event_EventArgs $args)
    {
        if (!$this->compatibilityLayerRootPath || !$this->compatibilityLayerBaseNamespace) {
            return null;
        }

        // Find all compatibility layers for the requested controller name
        $compatibilityLayers = new ArrayCollection();
        $iterator = new \DirectoryIterator($this->getPluginPath() . $this->compatibilityLayerRootPath);
        foreach ($iterator as $file) {
            if (!$file->isFile()) {
                continue;
            }

            // Parse file name and compare it to the name of the requested controller
            preg_match('/^((.*)\\d{8})\\.php/', $file->getFilename(), $matches);
            if (count($matches) !== 3 || mb_strtolower($matches[2]) !== mb_strtolower($args->get('controllerName'))) {
                continue;
            }

            // Create layer and check its version
            $fullLayerClass = $this->compatibilityLayerBaseNamespace . '\\' . $matches[1];
            $layer = new $fullLayerClass();
            if (version_compare($args->get('requiredVersion'), $layer->getVersion(), '<=')) {
                $compatibilityLayers->add($layer);
            }
        }

        return $compatibilityLayers;
    }

    /**
     * Calls the 'filterLoggedResponseJson()' method and passes it the request contained in
     * the event arguments as well as the $args' return value. Finally its return value is returned.
     *
     * @param \Enlight_Event_EventArgs $args
     * @return array|null
     */
    public function onFilterLoggedResponseJson(\Enlight_Event_EventArgs $args)
    {
        $responseJson = $args->getReturn();
        $request = $args->get('request');
        $filteredResponseJson = $this->filterLoggedResponseJson($responseJson, $request);

        return $filteredResponseJson;
    }

    /**
     * Calls the 'shouldLogRequest()' method and passes it the request contained in
     * the event arguments. Finally its return value is returned.
     *
     * @param \Enlight_Event_EventArgs $args
     * @return boolean|null
     */
    public function onShouldLogRequest(\Enlight_Event_EventArgs $args)
    {
        $request = $args->get('request');
        $shouldLog = $this->shouldLogRequest($request);

        return $shouldLog;
    }

    /**
     * Calls the abstract 'applyCustomRouting()' method and passes it the request contained in
     * the event arguments. Finally its return value is returned.
     *
     * @param \Enlight_Event_EventArgs $args
     * @return string|null
     */
    public function onApiControllerRouting(\Enlight_Event_EventArgs $args)
    {
        $request = $args->get('request');
        $controllerName = $this->applyCustomRouting($request);

        return $controllerName;
    }
}
