<?php

declare(strict_types=1);

namespace Inpsyde\MultilingualPress\Module\Redirect\Redirector;

use Inpsyde\MultilingualPress\Framework\Http\Request;
use Inpsyde\MultilingualPress\Module\Redirect\AcceptLanguageParser;
use Inpsyde\MultilingualPress\Module\Redirect\NoredirectPermalinkFilter;
use Inpsyde\MultilingualPress\Module\Redirect\NoRedirectStorage\NoRedirectStorage;
use Inpsyde\MultilingualPress\Module\Redirect\RedirectTarget\LanguageNegotiator;
use Inpsyde\MultilingualPress\Module\Redirect\RedirectTarget\RedirectTarget;

use function Inpsyde\MultilingualPress\callExit;
use function Inpsyde\MultilingualPress\siteLanguageTag;

class PhpRedirector implements Redirector
{
    /**
     * @var LanguageNegotiator
     */
    private $languageNegotiator;

    /**
     * @var Request
     */
    private $request;

    /**
     * @var NoRedirectStorage
     */
    private $noRedirectStorage;

    /**
     * @var AcceptLanguageParser
     */
    private $acceptLanguageParser;

    public function __construct(
        LanguageNegotiator $languageNegotiator,
        NoRedirectStorage $noRedirectStorage,
        Request $request,
        AcceptLanguageParser $acceptLanguageParser
    ) {

        $this->languageNegotiator = $languageNegotiator;
        $this->noRedirectStorage = $noRedirectStorage;
        $this->request = $request;
        $this->acceptLanguageParser = $acceptLanguageParser;
    }

    /**
     * @inheritdoc
     */
    public function redirect()
    {
        $value = (string)$this->request->bodyValue(
            NoredirectPermalinkFilter::QUERY_ARGUMENT,
            INPUT_GET,
            FILTER_SANITIZE_SPECIAL_CHARS
        );

        if ($value !== '') {
            $this->noRedirectStorage->addLanguage($value);
            return;
        }

        if ($this->requestLanguageIsSameAsCurrentSiteLanguage()) {
            return;
        }

        $target = $this->languageNegotiator->redirectTarget();

        if (!$target->url()) {
            /**
             * Do Action if Target was not Found
             *
             * @param RedirectTarget $target
             */
            do_action(self::ACTION_TARGET_NOT_FOUND, $target);
            return;
        }

        $this->noRedirectStorage->addLanguage($target->language());

        $requestUrl = $this->request->serverValue('QUERY_STRING');
        $url = !$requestUrl ? $target->url() : "{$target->url()}&{$requestUrl}";

        //phpcs:disable WordPressVIPMinimum.Security.ExitAfterRedirect.NoExit
        //phpcs:disable WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
        wp_redirect($url);
        callExit();
        //phpcs:enable
    }

    /**
     * Check if the Request language coming from 'Accept-Language' header
     * is the same as the current site language
     *
     * @return bool
     */
    protected function requestLanguageIsSameAsCurrentSiteLanguage(): bool
    {
        $requestAcceptLanguageHeader = $this->request->header('Accept-Language');
        $acceptLanguage = $this->acceptLanguageParser->parseHeader($requestAcceptLanguageHeader);
        $currentSiteLanguage = strtok(siteLanguageTag(get_current_blog_id()), '-');

        if (!empty($acceptLanguage) && key($acceptLanguage) === $currentSiteLanguage) {
            return true;
        }

        return false;
    }
}
