<?php

declare(strict_types=1);
/**
 * Created by Aurélien RICHAUD (31/07/2019 11:03).
 */
require_once __DIR__
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . 'classes'
    . \DIRECTORY_SEPARATOR . 'OAuthAccessToken.php';
require_once __DIR__
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . 'classes'
    . \DIRECTORY_SEPARATOR . 'OAuthAuthCode.php';
require_once __DIR__
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . 'classes'
    . \DIRECTORY_SEPARATOR . 'OAuthClient.php';

class MyvetshopcliniqueAuthorizeModuleFrontController extends FrontController
{
    /**
     * @var bool
     */
    public $auth = false;

    /**
     * @var bool
     */
    public $ssl = true;

    protected function processSubmitLogin(): void
    {
        \assert(
            null !== $this->context->cookie
            && null !== $this->context->cart
        );

        \Hook::exec('actionAuthenticationBefore');
        $passwd = \Tools::getValue('passwd');
        if (!\is_string($passwd)) {
            $passwd = '';
        }
        $email = \Tools::getValue('email');
        if (!\is_string($email)) {
            $email = '';
        }

        $passwd = \trim($passwd);
        $_POST['passwd'] = null;
        $email = \trim($email);
        if (empty($email)) {
            $this->errors[] = Tools::displayError('An email address required.');
        } elseif (!Validate::isEmail($email)) {
            $this->errors[] = Tools::displayError('Invalid email address.');
        } elseif (empty($passwd)) {
            $this->errors[] = Tools::displayError('Password is required.');
        } elseif (!Validate::isPlaintextPassword($passwd)) {
            $this->errors[] = 'Veuillez vérifier votre identifiant et votre mot de passe.';
        } else {
            $customer = new Customer();
            $authentication = $customer->getByEmail($email, $passwd);
            if (!\is_object($authentication) || !Validate::isLoadedObject($authentication)) {
                $this->errors[] = Tools::displayError('Authentication failed.');
            } elseif (!$authentication->active) {
                $this->errors[] = Tools::displayError('Your account isn\'t available at this time, please contact us');
            } else {
                if (!$customer->id) {
                    throw new \Exception("Erreur d'authentification, contactez le SAV");
                }
                // $this->context->cookie->id_compare = isset($this->context->cookie->id_compare) ? $this->context->cookie->id_compare : CompareProduct::getIdCompareByIdCustomer($customer->id);
                $this->context->cookie->id_customer = (int) $customer->id;
                $this->context->cookie->customer_lastname = $customer->lastname;
                $this->context->cookie->customer_firstname = $customer->firstname;
                $this->context->cookie->logged = true;
                $customer->logged = true;
                $this->context->cookie->mobile_app = 1;
                $this->context->cookie->is_guest = $customer->isGuest();
                $this->context->cookie->passwd = $customer->passwd;
                $this->context->cookie->email = $customer->email;

                // Add customer to the context
                $this->context->customer = $customer;

                if (
                    Configuration::get('PS_CART_FOLLOWING')
                    && (
                        empty($this->context->cookie->id_cart)
                        || 0 == Cart::getNbProducts($this->context->cookie->id_cart)
                    )
                    && $id_cart = (int) Cart::lastNoneOrderedCart($this->context->customer->id)
                ) {
                    $this->context->cart = new Cart($id_cart);
                } else {
                    $id_carrier = (int) $this->context->cart->id_carrier;
                    $this->context->cart->id_carrier = 0;
                    $this->context->cart->setDeliveryOption(null);
                    $this->context->cart->id_address_delivery = (int) Address::getFirstCustomerAddressId(
                        (int) $customer->id
                    );
                    $this->context->cart->id_address_invoice = (int) Address::getFirstCustomerAddressId(
                        (int) $customer->id
                    );
                }
                $this->context->cart->id_customer = (int) $customer->id;
                $this->context->cart->secure_key = $customer->secure_key;

                if ($this->ajax && isset($id_carrier) && $id_carrier && Configuration::get('PS_ORDER_PROCESS_TYPE')) {
                    $delivery_option = [$this->context->cart->id_address_delivery => $id_carrier . ','];
                    $this->context->cart->setDeliveryOption($delivery_option);
                }

                $this->context->cart->save();
                $this->context->cookie->id_cart = (int) $this->context->cart->id;
                $this->context->cookie->write();
                $this->context->cart->autosetProductAddress();

                Hook::exec('actionAuthentication', ['customer' => $this->context->customer]);

                // Login information have changed, so we check if the cart rules still apply
                CartRule::autoRemoveFromCart($this->context);
                CartRule::autoAddToCart($this->context);

                return;
            }
        }

        throw new \Exception(\strval($this->errors[0] ?? 'Logic exception'));
    }

    public function run(): void
    {
        $this->init();

        \assert(
            null !== $this->context->cookie
            && null !== $this->context->customer
        );

        // Enregistre les informations OAuth dans le cookie
        if (Tools::getValue('response_type')) {
            $this->context->cookie->response_type = Tools::getValue('response_type');
        }
        if (Tools::getValue('client_id')) {
            $this->context->cookie->client_id = Tools::getValue('client_id');
        }
        if (Tools::getValue('client_secret')) {
            $this->context->cookie->client_secret = Tools::getValue('client_secret');
        }
        if (Tools::getValue('redirect_uri')) {
            $this->context->cookie->redirect_uri = Tools::getValue('redirect_uri');
        }
        if (Tools::getValue('scope')) {
            $this->context->cookie->scope = Tools::getValue('scope');
        }
        $this->context->cookie->update();

        // Paramètres obligatoires
        if (!$this->context->cookie->response_type
            || !$this->context->cookie->client_id
            || !$this->context->cookie->redirect_uri
            || !$this->context->cookie->scope) {
            \header('HTTP/1.1 400 Bad Request');
            exit;
        }

        try {
            $client = OAuthClient::getByRandomId($this->context->cookie->client_id);
        } catch (PrestaShopDatabaseException $e) {
            $client = null;
        } catch (PrestaShopException $e) {
            $client = null;
        }

        // ///////////////////////////////////////
        // Client invalide
        if (!$client) {
            \header('HTTP/1.1 400 Bad Request');
            $this->ajaxRender(
                \json_encode(
                    [
                        'errors' => ['client not found'],
                    ]
                ) ?: ''
            );

            return;
        }

        // ///////////////////////////////////////
        // RedirectUri invalide
        /** @var OAuthClient $client */
        if (!\in_array($this->context->cookie->redirect_uri, \explode(',', $client->redirect_uris))) {
            \header('HTTP/1.1 403 Forbidden');
            $this->ajaxRender(
                \json_encode(
                    [
                        'errors' => ['redirect_uri invalide'],
                    ]
                ) ?: ''
            );

            return;
        }

        $this->authRedirection = true;

        $_POST['SubmitLogin'] = 1;
        $_POST['email'] = '';
        $_POST['passwd'] = '';

        if (!isset($_SERVER['HTTP_AUTHORIZATION'])) {
            $headers = getallheaders();
            if (isset($headers['authorization'])) {
                $_SERVER['HTTP_AUTHORIZATION'] = $headers['authorization'];
            } elseif (isset($headers['Authorization'])) {
                $_SERVER['HTTP_AUTHORIZATION'] = $headers['Authorization'];
            }
        }

        if (isset($_SERVER['HTTP_AUTHORIZATION']) && 0 === \stripos($_SERVER['HTTP_AUTHORIZATION'], 'basic ')) {
            $exploded = \explode(':', \base64_decode(\substr($_SERVER['HTTP_AUTHORIZATION'], 6)), 2);
            if (2 == \count($exploded)) {
                list($un, $pw) = $exploded;

                // Injection dans les variables POST
                $_POST['email'] = \trim($un);
                $_POST['passwd'] = $pw;
            }
        }

        try {
            $this->processSubmitLogin();
        } catch (Exception $e) {
            \header('HTTP/1.1 403 Forbidden');
            $this->ajaxRender(
                \json_encode(
                    [
                        'errors' => [$e->getMessage()],
                    ]
                ) ?: ''
            );

            return;
        }

        // Création d'un AuthCode
        \assert(
            null !== $this->context->cookie
            && null !== $this->context->customer
        );

        try {
            $authCode = new OAuthAuthCode();
            $authCode->client_id = $client->id_oauth_client;
            $authCode->id_customer = $this->context->customer->id;
            $authCode->redirect_uri = $this->context->cookie->redirect_uri;
            $authCode->created = time();
            $authCode->expires = time() + 15 * 60; // 15 minutes
        } catch (PrestaShopDatabaseException $e) {
            \header('HTTP/1.1 500 Internal Server Error');
            $this->ajaxRender(
                \json_encode(
                    [
                        'errors' => [$e->getMessage()],
                    ]
                ) ?: ''
            );

            return;
        } catch (PrestaShopException $e) {
            \header('HTTP/1.1 500 Internal Server Error');
            $this->ajaxRender(
                \json_encode(
                    [
                        'errors' => [$e->getMessage()],
                    ]
                ) ?: ''
            );

            return;
        }

        // Sauvegarde l'AuthCode
        try {
            $authCode->save();
        } catch (PrestaShopException $e) {
            \header('HTTP/1.1 500 Internal Server Error');
            $this->ajaxRender(
                \json_encode(
                    [
                        'errors' => [$e->getMessage()],
                    ]
                ) ?: ''
            );

            return;
        }

        // ///////////////////////////////////////
        // / Redirige vers l'URL de retour
        \header('HTTP/1.1 200 OK');
        $this->ajaxRender(
            \json_encode(
                [
                    'authcode' => $authCode->token,
                    'created' => $authCode->created,
                    'expires' => $authCode->expires,
                ]
            ) ?: ''
        );
    }

    /**
     * Réécriture de la méthode display (pas besoin de rendre un template, le controller doit être utilisé en ajax
     */
    public function display(): bool
    {
        return true;
    }
}
