<?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;

    /**
     * Process login
     */
    protected function processSubmitLogin(): void
    {
        Hook::exec('actionBeforeAuthentication');
        $passwd = trim(Tools::getValue('passwd'));
        $_POST['passwd'] = null;
        $email = trim(Tools::getValue('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::isPasswd($passwd)) {
            $this->errors[] = 'Veuillez vérifier votre identifiant et votre mot de passe.';
        } else {
            $customer = new Customer();
            /** @var Customer|false $authentication */
            $authentication = $customer->getByEmail(trim($email), trim($passwd));
            if (!$authentication || !$authentication->id) {
                $this->errors[] = Tools::displayError('Authentication failed.');
            } elseif (isset($authentication->active) && !$authentication->active) {
                $this->errors[] = Tools::displayError('Your account isn\'t available at this time, please contact us');
            } else {
                $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 = 1;
                $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);

                // Auth OK
                return;
            }
        }

        // Auth : Error
        header('HTTP/1.0 403 Forbidden');
        $return = [
            'errors' => $this->errors,
        ];
        $this->ajaxDie(Tools::jsonEncode($return));
    }

    public function init(): void
    {
        /////////////////////////////////////////
        // 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.0 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.0 400 Bad Request');
            $this->ajaxDie(
                Tools::jsonEncode(
                    [
                        'errors' => ['client not found'],
                    ]
                )
            );
        }

        /////////////////////////////////////////
        // RedirectUri invalide
        /** @var OAuthClient $client */
        if (!in_array($this->context->cookie->redirect_uri, explode(',', $client->redirect_uris))) {
            header('HTTP/1.0 403 Forbidden');
            $this->ajaxDie(
                Tools::jsonEncode(
                    [
                        'errors' => ['redirect_uri invalide'],
                    ]
                )
            );
        }

        $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;
            }
        }

        parent::init();

        $this->processSubmitLogin();

        /////////////////////////////////////////
        /// Création d'un AuthCode
        ///

        $authCode = null;
        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->scope = $this->context->cookie->scope;
            $authCode->created = time();
            $authCode->expires = time() + 15 * 60; // 15 minutes
        } catch (PrestaShopDatabaseException $e) {
            header('HTTP/1.0 500 Internal Server Error');
            $this->ajaxDie(
                Tools::jsonEncode(
                    [
                        'errors' => [$e->getMessage()],
                    ]
                )
            );
        } catch (PrestaShopException $e) {
            header('HTTP/1.0 500 Internal Server Error');
            $this->ajaxDie(
                Tools::jsonEncode(
                    [
                        'errors' => [$e->getMessage()],
                    ]
                )
            );
        }

        // Sauvegarde l'AuthCode
        try {
            $authCode->save();
        } catch (PrestaShopException $e) {
            header('HTTP/1.0 500 Internal Server Error');
            $this->ajaxDie(
                Tools::jsonEncode(
                    [
                        'errors' => [$e->getMessage()],
                    ]
                )
            );
        }

        /////////////////////////////////////////
        /// Redirrige vers l'URL de retour
        // TODO : Rendre compatible ajax / non ajax
        $this->ajaxDie(
            Tools::jsonEncode(
                [
                    'authcode' => $authCode->token,
                    'created' => $authCode->created,
                    'expires' => $authCode->expires,
                ]
            )
        );
    }
}
