<?php

declare(strict_types=1);

/**
 * Created by Aurélien RICHAUD (30/08/2018 16:51).
 */
class Cookie extends CookieCore
{
    /**
     * @var OAuthAccessToken|null
     */
    protected $accessToken;

    /**
     * @var OAuthAccessTokenCookie|null
     */
    protected $accessTokenCookie;

    /**
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function loadAccessToken(): void
    {
        require_once _PS_MODULE_DIR_ . 'myvetshopclinique/classes/OAuthAccessToken.php';
        require_once _PS_MODULE_DIR_ . 'myvetshopclinique/classes/OAuthAccessTokenCookie.php';

        // Extraction du token de la requête
        $token = OAuthAccessToken::getTokenFromRequest();
        if (!$token) {
            return;
        }

        // Vérification de la validité du token
        $accessToken = OAuthAccessToken::getByToken($token);
        if (!$accessToken || $accessToken->expires < \time()) {
            return;
        }

        // Token valide
        $this->accessToken = $accessToken;
    }

    /**
     * @param string $path
     * @param int|null $expire
     * @param string[]|null $shared_urls
     * @param bool $standalone
     * @param bool $secure
     *
     * {@inheritDoc}
     */
    public function __construct(string $name, $path = '', $expire = null, $shared_urls = null, $standalone = false, $secure = false)
    {
        $this->loadAccessToken();

        parent::__construct($name, $path, $expire, $shared_urls, $standalone, $secure);
    }

    public function logout(): void
    {
        $stock = [];
        if (isset($this->_content['response_type'], $this->_content['client_id'], $this->_content['redirect_uri'], $this->_content['scope'])
        ) {
            $stock['response_type'] = $this->_content['response_type'];
            $stock['client_id'] = $this->_content['client_id'];
            $stock['redirect_uri'] = $this->_content['redirect_uri'];
            $stock['scope'] = $this->_content['scope'];
        }

        parent::logout();

        if (\count($stock)) {
            $this->response_type = $stock['response_type'];
            $this->client_id = $stock['client_id'];
            $this->redirect_uri = $stock['redirect_uri'];
            $this->scope = $stock['scope'];
        }
    }

    /**
     * @param bool $nullValues
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function update($nullValues = false): void
    {
        \assert($this->cipherTool instanceof PhpEncryption);
        \assert(\is_string($this->_name));

        if ($this->accessToken) {
            $this->accessTokenCookie = OAuthAccessTokenCookie::getByTokenAndName(
                $this->accessToken->token,
                $this->_name
            );

            // Si le cookie existe, n'est pas expiré et contient une donnée,
            // on remplace les valeurs par celles en base !
            if (
                $this->accessTokenCookie
                && $this->accessTokenCookie->expires > time()
                && $this->accessTokenCookie->value
            ) {
                $_COOKIE[$this->_name] = $this->cipherTool->encrypt($this->accessTokenCookie->value);

                /** @var array{
                 *     expires?: int,
                 *     path?: string,
                 *     domain?: string,
                 *     secure?: bool,
                 *     httponly?: bool,
                 *     samesite?: 'Lax'|'lax'|'None'|'none'|'Strict'|'strict'
                 * } $cookieOptions
                 */
                $cookieOptions = [
                    'expires' => $this->_expire,
                    'path' => $this->_path,
                    'domain' => $this->_domain,
                    'secure' => $this->_secure,
                    'httponly' => true,
                    'samesite' => $this->_sameSite,
                ];

                // Force le cookie
                setcookie(
                    $this->_name,
                    $_COOKIE[$this->_name],
                    $cookieOptions,
                );
            } elseif (null === $this->accessTokenCookie) {
                $this->accessTokenCookie = new OAuthAccessTokenCookie();
                $this->accessTokenCookie->token = $this->accessToken->token;
                $this->accessTokenCookie->name = $this->_name;
                $this->accessTokenCookie->value = null;
                $this->accessTokenCookie->expires = 0;
                $this->encryptAndSetCookie($_COOKIE[$this->_name]);
            }
        }

        parent::update($nullValues);
    }

    /**
     * @param string|null $cookie
     *
     * @throws PrestaShopException
     */
    protected function encryptAndSetCookie($cookie = null): bool
    {
        \assert(\is_string($this->_name));
        \assert(\is_int($this->_expire));

        $ret = parent::encryptAndSetCookie($cookie);

        // Sauvegarde en base au besoin
        if ($this->accessToken && $this->accessTokenCookie) {
            $this->accessTokenCookie->expires = $this->_expire;
            $this->accessTokenCookie->value = $cookie;

            Db::getInstance()->connect();
            $this->accessTokenCookie->save();
        }

        return $ret;
    }
}
