<?php

declare(strict_types=1);

/**
 * Created by Aurélien RICHAUD (01/08/2019 12:16).
 */
require_once __DIR__ . \DIRECTORY_SEPARATOR . 'ApiFrontController.php';
require_once __DIR__
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . 'classes'
    . \DIRECTORY_SEPARATOR . 'Clinique.php';

class MyvetshopcliniqueOrdersModuleFrontController extends ApiFrontController
{
    /**
     * @return array<string, mixed>
     */
    protected function serializeOrder(Order $order): array
    {
        $context = Context::getContext();
        \assert(null !== $context);
        $langId = (int) $context->language->id;

        $orderState = new OrderState($order->current_state);
        $orderCarrier = Carrier::getCarrierByReference($order->id_carrier);

        $ret = [
            'id' => $order->id,
            'id_address_delivery' => $order->id_address_delivery,
            'id_address_invoice' => $order->id_address_invoice,
            'id_cart' => $order->id_cart,
            'id_currency' => $order->id_currency,
            'id_lang' => $order->id_lang,
            'id_customer' => $order->id_customer,
            'id_carrier' => $order->id_carrier,
            'carrier' => [
                'id' => $orderCarrier->id,
                'name' => $orderCarrier->name,
                'is_free' => (bool) $orderCarrier->is_free,
                'url' => $orderCarrier->url,
                'delay' => $orderCarrier->delay,
                'domicile' => (bool) (!$orderCarrier->domicile),
            ],
            'current_state' => $order->current_state,
            'module' => $order->module,
            'invoice_number' => $order->invoice_number,
            'invoice_date' => $order->invoice_date,
            'delivery_number' => $order->delivery_number,
            'delivery_date' => $order->delivery_date,
            'valid' => $order->valid,
            'date_add' => $order->date_add,
            'date_upd' => $order->date_upd,
            'shipping_number' => $order->shipping_number,
            'id_shop_group' => $order->id_shop_group,
            'id_shop' => $order->id_shop,
            'secure_key' => $order->secure_key,
            'payment' => $order->payment,
            'recyclable' => $order->recyclable,
            'gift' => $order->gift,
            'gift_message' => $order->gift_message,
            'mobile_theme' => $order->mobile_theme,
            'total_discounts' => $order->total_discounts,
            'total_discounts_tax_incl' => $order->total_discounts_tax_incl,
            'total_discounts_tax_excl' => $order->total_discounts_tax_excl,
            'total_paid' => $order->total_paid,
            'total_paid_tax_incl' => $order->total_paid_tax_incl,
            'total_paid_tax_excl' => $order->total_paid_tax_excl,
            'total_paid_real' => $order->total_paid_real,
            'total_products' => $order->total_products,
            'total_products_wt' => $order->total_products_wt,
            'total_shipping' => $order->total_shipping,
            'total_shipping_tax_incl' => $order->total_shipping_tax_incl,
            'total_shipping_tax_excl' => $order->total_shipping_tax_excl,
            'carrier_tax_rate' => $order->carrier_tax_rate,
            'total_wrapping' => $order->total_wrapping,
            'total_wrapping_tax_incl' => $order->total_wrapping_tax_incl,
            'total_wrapping_tax_excl' => $order->total_wrapping_tax_excl,
            'round_mode' => $order->round_mode,
            'round_type' => $order->round_type,
            'conversion_rate' => $order->conversion_rate,
            'reference' => $order->reference,
            'products' => [],
            'order_state' => [
                'id' => $orderState->id,
                'unremovable' => $orderState->unremovable,
                'delivery' => $orderState->delivery,
                'hidden' => $orderState->hidden,
                'send_email' => $orderState->send_email,
                'module_name' => $orderState->module_name,
                'invoice' => $orderState->invoice,
                'color' => $orderState->color,
                'logable' => $orderState->logable,
                'shipped' => $orderState->shipped,
                'paid' => $orderState->paid,
                'pdf_delivery' => $orderState->pdf_delivery,
                'pdf_invoice' => $orderState->pdf_invoice,
                'deleted' => $orderState->deleted,
                'name' => $orderState->name[$langId] ?? '',
                'template' => $orderState->template,
            ],
            'history' => [],
        ];

        foreach ($order->getProductsDetail() as $productDetail) {
            $product = [
                'id' => $productDetail['id_order_detail'],
                'product_id' => $productDetail['product_id'],
                'product_attribute_id' => $productDetail['product_attribute_id'],
                'product_name' => $productDetail['product_name'],
                'product_reference' => $productDetail['product_reference'],
                'product_ean13' => $productDetail['product_ean13'],
                'product_upc' => $productDetail['product_upc'],
                'unit_price_tax_excl' => $productDetail['unit_price_tax_excl'],
                'unit_price_tax_incl' => $productDetail['unit_price_tax_incl'],
                'product_quantity' => $productDetail['product_quantity'],
                'total_price_tax_incl' => $productDetail['total_price_tax_incl'],
                'total_price_tax_excl' => $productDetail['total_price_tax_excl'],
            ];

            $ret['products'][] = $product;
        }

        foreach ($order->getHistory($this->context->language->id) as $orderHistory) {
            $ret['history'][] = $orderHistory;
        }

        return $ret;
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionLastOrder(): array
    {
        $customer = $this->context->customer;

        $lastOrderId = Db::getInstance(false)
            ->getValue('SELECT `id_order` FROM `' . _DB_PREFIX_ . 'orders` WHERE `id_customer` = ' . (int) $customer->id . ' ORDER BY `id_order` DESC');

        if (!$lastOrderId) {
            header('HTTP/1.0 500 Internal Server Error');

            return [
                'message' => 'No order',
            ];
        }

        $order = new Order((int) $lastOrderId);

        return $this->serializeOrder($order);
    }

    /**
     * @return array<int, array<string, mixed>>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionLastOrders(): array
    {
        $customer = $this->context->customer;

        $lastOrdersId = Db::getInstance(false)
            ->executeS('SELECT `id_order`'
                . ' FROM `' . _DB_PREFIX_ . 'orders`'
                . ' WHERE `id_customer` = ' . (int) $customer->id . ' ORDER BY `id_order` DESC LIMIT 10');

        if (!is_array($lastOrdersId)) {
            $lastOrdersId = [];
        }

        $ret = [];
        foreach ($lastOrdersId as $row) {
            $order = new Order($row['id_order']);
            $ret[] = $this->serializeOrder($order);
        }

        return $ret;
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionOrder(): array
    {
        $customer = $this->context->customer;

        $orderId = Tools::getValue('order_id', Tools::getValue('id_order', 0));

        if (\is_string($orderId) || \is_int($orderId)) {
            $orderId = (int) $orderId;
        } else {
            $orderId = 0;
        }

        $orderIdFiltered = Db::getInstance(false)
            ->getValue(
                'SELECT `id_order`'
                . ' FROM `' . _DB_PREFIX_ . 'orders`'
                . ' WHERE `id_customer` = ' . (int) $customer->id
                . ' AND `id_order` = ' . $orderId
            );

        if (!$orderIdFiltered) {
            return [];
        }

        $order = new Order((int) $orderIdFiltered);

        return $this->serializeOrder($order);
    }

    /**
     * @return string[]
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionOrderPaid(): array
    {
        $idCartRaw = Tools::getValue('id_cart', null);
        \assert(\is_string($idCartRaw) || \is_int($idCartRaw) || \is_null($idCartRaw));
        $idOrderRaw = Tools::getValue('id_order', null);
        \assert(\is_string($idOrderRaw) || \is_int($idOrderRaw) || \is_null($idOrderRaw));
        $idModuleRaw = Tools::getValue('id_module', 0);
        \assert(\is_string($idModuleRaw) || \is_int($idModuleRaw));
        $keyRaw = Tools::getValue('key', null);
        \assert(\is_string($keyRaw) || \is_null($keyRaw));

        $idCart = \intval($idCartRaw);
        $idOrder = \intval($idOrderRaw);
        $idModule = \intval($idModuleRaw);
        $key = \strval($keyRaw);

        $cart = new Cart($idCart);

        if ($cart->id_customer != $this->context->customer->id || $cart->secure_key != $key) {
            \header('HTTP/1.0 403 Forbidden');

            return ['error' => 'id_customer,secure_key'];
        }

        $ret = [
            'status' => Tools::getValue('status'),
            'id_order' => (int) $idOrder,
            'id_cart' => (int) $idCart,
        ];

        if (!$idOrder) {
            $idOrder = Order::getIdByCartId((int) $idCart) ?: 0;
        }

        if ($idOrder) {
            $order = new Order($idOrder);
            $module = Module::getInstanceById((int) $idModule);
            if (!$module || $order->module != $module->name) {
                \header('HTTP/1.0 403 Forbidden');

                return ['error' => 'module_name'];
            }

            $orderStatus = $order->getCurrentOrderState();
            if ($orderStatus && $orderStatus->paid) {
                $ret['status'] = 'success';
            } else {
                $ret['status'] = 'reject';
            }

            // Ajout d'une note dans la commande pour indiquer qu'elle vient de l'application mobile
            $msg = new Message();
            $message = \strip_tags("Cette commande a été passée depuis l'application mobile", '<br>');
            if (Validate::isCleanHtml($message)) {
                $msg->message = $message;
                $msg->id_cart = (int) $idCart;
                $msg->id_customer = (int) $order->id_customer;
                $msg->id_order = (int) $order->id;
                $msg->private = true;
                try {
                    $msg->add();
                } catch (PrestaShopDatabaseException $e) {
                    // Inhibiteur d'erreur
                } catch (PrestaShopException $e) {
                    // Inhibiteur d'erreur
                }
            }
        }

        \header('Content-Type: text/html'); ?>
        <!doctype html>
        <html lang="en">
        <head>
            <meta charset="utf-8">
            <script type="text/javascript">
                window.orderPaid = <?php echo \json_encode($ret); ?>;
            </script>
        </head>
        <body style="color: white; background-color: white;">
        Fin du processus de commande
        </body>
        </html>
        <?php
        exit;
    }

    /**
     * @return array<string, mixed>
     */
    protected function actionPayOrder(): array
    {
        $cart = $this->context->cart;

        if (0 == count($cart->getProducts())) {
            return ['success' => false, 'form' => '', 'message' => "Impossible de passer commande d'un panier vide."];
        }

        /** @var PaymentModule $paymentModule */
        $paymentModule = Module::getInstanceByName('myvetshoppayment');

        \assert(\method_exists($paymentModule, 'hookPayment'));

        try {
            header('Content-Type: text/html'); ?>
            <!doctype html>
            <html lang="en">
            <head>
                <meta charset="utf-8">
                <script type="text/javascript">
                    window.onload = function () {
                        document.forms[0].submit();
                    }
                </script>
            </head>
            <body style="color: white; background-color: white;">
            <?php
            echo $paymentModule->hookPayment(
                [
                    'cart' => $cart,
                    'url_retour_ok' => Tools::getHttpHost(true, true, true) . _MODULE_DIR_ . 'myvetshoppayment/submit.php?id_cart=' . (int) $cart->id . '&app=1',
                    'url_retour_err' => Tools::getHttpHost(true, true, true) . _MODULE_DIR_ . 'myvetshoppayment/submit.php?id_cart=' . (int) $cart->id . '&app=1',
                ]
            ); ?>
            </body>
            </html>
            <?php
            exit;
        } catch (PrestaShopException $e) {
            return [
                'success' => false,
                'form' => '',
                'message' => $e->getMessage(),
            ];
        }
    }

    /**
     * @return array{success: bool, message: string}
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionPdfInvoice(): array
    {
        $idOrder = Tools::getValue('id_order', null);
        if ((!\is_string($idOrder) && !\is_int($idOrder)) || !$idOrder) {
            return ['success' => false, 'message' => 'Aucune commande sélectionnée'];
        }

        $order = new Order(\intval($idOrder));
        if ($order->id_customer != $this->context->customer->id) {
            return ['success' => false, 'message' => "Problème d'accès à la commande"];
        }

        Tools::redirectLink(
            '/index.php?controller=pdf-invoice&id_order='
            . (int) $order->id
            . '&secure_key=' . $order->secure_key
        );
        exit;
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionReorder(): array
    {
        $idOrder = Tools::getValue('id_order', null);

        if ((!\is_string($idOrder) && !\is_int($idOrder)) || !$idOrder) {
            return ['success' => false, 'message' => 'Aucune commande sélectionnée'];
        }

        $order = new Order(\intval($idOrder));
        if ($order->id_customer != $this->context->customer->id) {
            return ['success' => false, 'message' => "Problème d'accès à la commande"];
        }
        $originalCart = new Cart((int) $order->id_cart);

        $duplication = $originalCart->duplicate();

        if (\is_array($duplication)) {
            // Vérification réelle des stocks
            $manager = StockManagerFactory::getManager();
            $clinique = Clinique::getCliniqueByGroupId((int) $this->context->customer->id_default_group);

            if (!$clinique) {
                return ['success' => false, 'message' => 'Clinique non trouvée'];
            }

            foreach ($this->context->cart->getProducts() as $product) {
                $product_real_quantities = $manager->getProductRealQuantities(
                    $product['id_product'],
                    $product['id_product_attribute'],
                    [$clinique->id_warehouse],
                    true
                );

                if ($product_real_quantities < $product['cart_quantity']) {
                    // Supprime le produit du panier
                    $this->context->cart->updateQty(
                        (int) $product['cart_quantity'],
                        (int) $product['id_product'],
                        (int) $product['id_product_attribute'],
                        0,
                        'down'
                    );
                    $duplication['success'] = false;
                }
            }
        }

        if (!\is_array($duplication) || !Validate::isLoadedObject($duplication['cart'])) {
            return ['success' => false, 'message' => 'Impossible de repasser commande'];
        } elseif (!$duplication['success']) {
            return ['success' => false, 'message' => 'Certains produits ne sont plus disponibles'];
        } else {
            $this->context->cookie->id_cart = $duplication['cart']->id;
            $context = $this->context;
            $this->context->cart = $duplication['cart'];
            $this->context->cookie->id_cart = $this->context->cart->id;
            CartRule::autoAddToCart($context);
            // $this->context->cookie->write();

            return ['success' => true, 'message' => 'Commande re-passée', 'id_cart' => $duplication['cart']->id];
        }
    }

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

        $action = Tools::getValue('action', 'nothing');
        if (!\is_string($action)) {
            $action = 'nothing';
        }

        switch ($action) {
            case 'lastOrder':
                $ret = $this->actionLastOrder();
                break;

            case 'lastOrders':
                $ret = $this->actionLastOrders();
                break;

            case 'order':
                $ret = $this->actionOrder();
                break;

            case 'orderPaid':
                $ret = $this->actionOrderPaid();
                break;

            case 'payOrder':
                $ret = $this->actionPayOrder();
                break;

            case 'pdfInvoice':
                $ret = $this->actionPdfInvoice();
                break;

            case 'reOrder':
                $ret = $this->actionReorder();
                break;

            default:
                $ret = [];
        }

        echo \json_encode($ret, \JSON_PRETTY_PRINT);
    }
}
