<?php
declare(strict_types = 1);

namespace Zeroseven\Seo\Canonical;

use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use Zeroseven\Seo\Services\SettingsService;

/**
 * Class to add the canonical tag to the page
 */
class CanonicalGenerator extends \TYPO3\CMS\Seo\Canonical\CanonicalGenerator
{
    /**
     * Plugin configuration
     *
     * @var array
     */
    protected $config = [];

    public function __construct()
    {
        parent::__construct();

        $this->config = GeneralUtility::makeInstance(SettingsService::class)->getPluginConfig();
    }

    /**
     * @param $href
     */
    public function checkWhitelistCanonical(&$href): void
    {
        // If there is a configured canonical, do nothing
        if (empty($href) && $this->config['canonical']['mode'] === 'whitelist' && empty($this->checkContentFromPid()) && empty($this->checkForCanonicalLink())) {
            $href = $this->createWhitelistedCanonical();
        }
    }

    /**
     * @return string
     */
    protected function createWhitelistedCanonical(): string
    {
        return $this->typoScriptFrontendController->cObj->typoLink_URL([
            'parameter' => $this->typoScriptFrontendController->id . ',' . $this->typoScriptFrontendController->type,
            'forceAbsoluteUrl' => true,
            'addQueryString' => true,
            'addQueryString.' => [
                'method' => 'GET',
                'exclude' => implode(
                    ',',
                    $this->getParamsToExcludeFromCanonicalUrl()
                )
            ]
        ]);
    }

    /**
     * @return array
     */
    protected function getParamsToExcludeFromCanonicalUrl(): array
    {
        // Get all params
        $allParams = ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) ? $GLOBALS['TYPO3_REQUEST']->getQueryParams() : [];

        // Collect allowed params and convert to an array
        $allowedParamsString = str_replace([',', ' '], ['&', ''], (string)$this->config['canonical']['allowedParameters']);
        parse_str($allowedParamsString, $allowedParams);

        // Collect exclude params
        $excludeParams = [];
        foreach ($allParams as $key => $value) {
            if (is_array($value)) {
                foreach ($value as $subKey => $subValue) {
                    if (!array_key_exists('*', (array)$allowedParams[$key]) && !array_key_exists($subKey, (array)$allowedParams[$key])) {
                        $excludeParams[] = sprintf('%s[%s]', $key, $subKey);
                    }
                }
            } elseif (!array_key_exists($key, $allowedParams)) {
                $excludeParams[] = $key;
            }
        }

        return $excludeParams;
    }
}