<?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 . 'Animal.php';
require_once __DIR__
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . 'classes'
    . \DIRECTORY_SEPARATOR . 'AnimalSac.php';
require_once __DIR__
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . 'classes'
    . \DIRECTORY_SEPARATOR . 'Recommandation.php';
require_once __DIR__
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . 'class'
    . \DIRECTORY_SEPARATOR . 'CricCrocApi.php';
require_once __DIR__
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . 'Service'
    . \DIRECTORY_SEPARATOR . 'RecommandationManagerApi' . \DIRECTORY_SEPARATOR . 'RecommandationController.php';
require_once __DIR__
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . '..'
    . \DIRECTORY_SEPARATOR . 'vendor'
    . \DIRECTORY_SEPARATOR . 'autoload.php';

use Myvetshop\Module\Clinique\Handler\RecommandationHandler;

class MyvetshopcliniqueAnimalModuleFrontController extends ApiFrontController
{
    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     */
    protected function serializeAnimal(Animal $animal): array
    {
        $file_name = 'a_' . md5($animal->id . 'animal');
        $photo_url = null;

        if (is_file(_PS_UPLOAD_DIR_ . $file_name . '.jpg')) {
            $photo_url = 'https://' . $_SERVER['HTTP_HOST'] . '/upload/' . $file_name . '.jpg?t=' . filemtime(_PS_UPLOAD_DIR_ . $file_name . '.jpg');
        }

        $recoArray = $this->serializeRecommandation(new Recommandation($animal->getIdRecoCricCroc()));

        $sacs = [];
        $sacsActuels = $animal->getSacsActuels();
        if (is_array($sacsActuels)) {
            $sacs = array_map([$this, 'serializeAnimalSac'], $sacsActuels);
        }

        return [
            'id_animal' => $animal->id,
            'espece' => $animal->espece,
            'nom' => $animal->nom,
            'race' => $animal->race,
            'id_gender' => $animal->id_gender,
            'robe' => $animal->robe,
            'date_naissance' => $animal->date_naissance,
            'ration' => $animal->ration,
            'id_product' => $animal->id_product,
            'date_add' => $animal->date_add,
            'date_upd' => $animal->date_upd,
            'sacs' => $sacs,
            'photo' => $photo_url,
            'reco' => $recoArray,
        ];
    }

    /**
     * @param array{id_product: int} $animalSac
     *
     * @return array<string, mixed>
     */
    protected function serializeAnimalSac(array $animalSac): array
    {
        $cover = Product::getCover($animalSac['id_product']);

        $link = new Link();
        $animalSac['cover_url'] = 'https://'
            . $link->getImageLink('mobileapp', $cover['id_image'], 'home_default');

        return $animalSac;
    }

    /**
     * @return array<string, mixed>
     */
    protected function serializeRecommandation(Recommandation $reco): array
    {
        $db = Db::getInstance(false);
        $discount_code = null;
        $result = $db->getRow(
            'SELECT `rule`.code AS discount_code
             FROM `' . _DB_PREFIX_ . 'cart_rule` `rule`
             WHERE `rule`.code = "' . $db->escape($reco->code_reco) . '"
             AND `rule`.quantity > 0
             AND `rule`.active = 1
             ');
        if ($result && is_array($result) && isset($result['discount_code'])) {
            $discount_code = $result['discount_code'];
        }

        return [
            'id' => $reco->id,
            'id_animal' => $reco->id_animal,
            'code_reco' => $reco->code_reco,
            'date_reco' => $reco->date_reco,
            'petname' => $reco->petname,
            'espece' => $reco->espece,
            'race' => $reco->race,
            'id_gender' => $reco->id_gender,
            'activite' => $reco->activite,
            'age' => $reco->age,
            'stade_physio' => $reco->stade_physio,
            'pathologie' => $reco->pathologie,
            'poids_actuel' => $reco->poids_actuel,
            'poids_ideal' => $reco->poids_ideal,
            'be' => $reco->be,
            'nbr_aliment' => $reco->nbr_aliment,
            'product_id_mvs1' => $reco->product_id_mvs1,
            'product_id_mvs2' => $reco->product_id_mvs2,
            'product_id_mvs3' => $reco->product_id_mvs3,
            'qte_aliment1' => $reco->qte_aliment1,
            'qte_aliment2' => $reco->qte_aliment2,
            'qte_aliment3' => $reco->qte_aliment3,
            'transition12' => $reco->transition12,
            'transition23' => $reco->transition23,
            'date_add' => $reco->date_add,
            'date_upd' => $reco->date_upd,
            'deleted' => $reco->deleted,
            'discount_code' => $discount_code,
        ];
    }

    /**
     * @return array<mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionCreate(): array
    {
        $animalRaw = \Tools::getValue('animal');
        if (!\is_array($animalRaw)) {
            $animalRaw = [];
        }

        $animal = new Animal();
        $animal->hydrate($animalRaw);
        $animal->id_customer = $this->context->customer->id;
        $animal->save();

        if (isset($_FILES['photo'])) {
            $errors = [];

            // Traitement de la mise à jour de la photo
            if ($error = ImageManager::validateUpload($_FILES['photo'], (int) Configuration::get('PS_PRODUCT_PICTURE_MAX_SIZE'))) {
                $errors[] = $error;
            }
            if (!($tmp_name = \tempnam(_PS_TMP_IMG_DIR_, 'PS')) || !\move_uploaded_file($_FILES['photo']['tmp_name'], $tmp_name)) {
                $errors[] = \Tools::displayError('An error occurred during the image upload process.');
            }
            $file_name = 'a_' . \md5($animal->id . 'animal');

            if (!$tmp_name) {
                throw new Exception('Le nom du fichier n\'est pas valide');
            }

            $src_info = \getimagesize($tmp_name);
            $tmp_name_square = (string) \tempnam(_PS_TMP_IMG_DIR_, 'PS');

            if (!\is_array($src_info)) {
                throw new Exception('Erreur lors de la récupération des infos de l\'image');
            }

            if (!isset($src_info[0]) || !isset($src_info[1])) {
                throw new Exception('Le format des infos de l\'image est invalide');
            }

            if (
                !ImageManager::cut(
                    /* @phpstan-ignore-next-line incohérance avec le code source prestashop */
                    $tmp_name,
                    $tmp_name_square,
                    \min($src_info[0], $src_info[1]),
                    \min($src_info[0], $src_info[1])
                )
            ) {
                $errors[] = \Tools::displayError("Impossible de retailler l'image");
            }
            if (\is_file(_PS_UPLOAD_DIR_ . $file_name . '.jpg')) {
                \unlink(_PS_UPLOAD_DIR_ . $file_name . '.jpg');
            }
            if (
                !ImageManager::resize(
                    $tmp_name_square,
                    _PS_UPLOAD_DIR_ . $file_name . '.jpg',
                    160,
                    160
                )
            ) {
                $errors[] = \Tools::displayError("Impossible de retailler l'image");
            }
            \unlink($tmp_name_square);
            \unlink($tmp_name);
        }

        return $this->serializeAnimal($animal);
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionDelete(): array
    {
        $animal = new Animal(\intval(\Tools::getValue('id')));

        if ($animal->deleted) {
            \header('HTTP/1.0 404 Not Found');

            return [];
        }

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

            return [];
        }

        $recommandation = $animal->getRecommandation();

        $animal->deleted = true;
        $result = $animal->save();

        // Si suppression de l'animal, suppression de la reco associé
        if ($result && $recommandation) {
            $recommandation->deleted = true;
            $recommandation->update();
        }

        return $this->serializeAnimal($animal);
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionGet(): array
    {
        $animal = new Animal(\intval(\Tools::getValue('id')));

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

            return [];
        }

        return $this->serializeAnimal($animal);
    }

    /**
     * @return array<int,mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionList(): array
    {
        $result = Db::getInstance(false)
            ->executeS(
                'SELECT a.*'
                . ' FROM `' . _DB_PREFIX_ . 'animal` a'
                . ' WHERE `a`.`id_customer` = ' . (int) $this->context->customer->id
                . ' AND `a`.`deleted` = 0'
            );

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

        $animaux = ObjectModel::hydrateCollection(
            Animal::class, $result
        );

        $ret = [];

        foreach ($animaux as $animal) {
            $ret[] = $this->serializeAnimal($animal);
        }

        return $ret;
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionUpdate(): array
    {
        $animal = new Animal(\intval(\Tools::getValue('id')));

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

            return [];
        }

        $animalRaw = \Tools::getValue('animal');

        if (\is_array($animalRaw)) {
            $animal->hydrate($animalRaw);
            $animal->id_customer = $this->context->customer->id;
            // todo: date de naissance invalide ?
            $animal->save();
        }

        if (isset($_FILES['photo'])) {
            $errors = [];

            // Traitement de la mise à jour de la photo
            if ($error = ImageManager::validateUpload($_FILES['photo'], (int) Configuration::get('PS_PRODUCT_PICTURE_MAX_SIZE'))) {
                $errors[] = $error;
            }
            if (
                !($tmp_name = (string) \tempnam(_PS_TMP_IMG_DIR_, 'PS'))
                || !\move_uploaded_file($_FILES['photo']['tmp_name'], $tmp_name)
            ) {
                $errors[] = \Tools::displayError('An error occurred during the image upload process.');
            }
            $file_name = (string) 'a_' . \md5($animal->id . 'animal');

            $src_info = \getimagesize((string) $tmp_name);

            if (!\is_array($src_info)) {
                throw new Exception('Erreur lors de la récupération des infos de l\'image');
            }

            if (!isset($src_info[0]) || !isset($src_info[1])) {
                throw new Exception('Format des infos de l\'image invalide');
            }

            $tmp_name_square = (string) \tempnam(_PS_TMP_IMG_DIR_, 'PS');
            if (
                !ImageManager::cut(
                    /* @phpstan-ignore-next-line incohérance avec le code source prestashop */
                    $tmp_name,
                    $tmp_name_square,
                    \min($src_info[0], $src_info[1]),
                    \min($src_info[0], $src_info[1]))
            ) {
                $errors[] = \Tools::displayError("Impossible de retailler l'image");
            }
            if (\is_file(_PS_UPLOAD_DIR_ . $file_name . '.jpg')) {
                \unlink(_PS_UPLOAD_DIR_ . $file_name . '.jpg');
            }
            if (
                !ImageManager::resize(
                    $tmp_name_square,
                    _PS_UPLOAD_DIR_ . $file_name . '.jpg',
                    160,
                    160)
            ) {
                $errors[] = \Tools::displayError("Impossible de retailler l'image");
            }
            \unlink($tmp_name_square);
            \unlink($tmp_name);
        }

        // var_dump($animal);die();
        return $this->serializeAnimal($animal);
    }

    /**
     * @return array<int,array<string, mixed>>|array<string, string>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionSearchSacDetail(): array
    {
        $context = \Context::getContext();
        \assert(null !== $context);

        $ret = [];

        $product = new Product(
            \intval(\Tools::getValue('id_product')),
            false,
            $context->language->id,
        );

        if (!AnimalSac::isCroquette((int) $product->id)) {
            \header('HTTP/1.0 400 Bad Request');

            return [
                'error' => "Ce produit n'est pas un sac de croquettes",
            ];
        }

        foreach ($product->getWsCombinations() as $row) {
            $combination = new Combination($row['id']);

            $attributeNames = $combination->getAttributesName($context->language->id);
            \assert(\is_array($attributeNames));

            $formats = \array_reduce(
                $attributeNames,
                function ($carry, $item) {
                    $carry[] = $item['name'];

                    return $carry;
                },
                []
            );

            $ret[] = [
                'id_order' => null,
                'id_product' => $combination->id_product,
                'id_product_attribute' => $combination->id,
                'date_achat' => null,
                'product_name' => \strval($product->name) . ' - Format : ' . \implode(', ', $formats),
                'product_reference' => $combination->reference,
                'product_ean13' => $combination->ean13,
            ];
        }

        return $ret;
    }

    /**
     * @return array<string, mixed>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionAssociate(): array
    {
        $animal = new Animal(\intval(\Tools::getValue('id')));

        if ($animal->id_customer != $this->context->customer->id) {
            header('HTTP/1.0 403 Forbidden');

            return [];
        }

        $idOrder = \intval(\Tools::getValue('id_order'));
        if ($idOrder) {
            $order = new Order($idOrder);
            if ($order->id_customer != $this->context->customer->id) {
                \header('HTTP/1.0 403 Forbidden');

                return [];
            }
        } else {
            $order = new Order();
        }
        $id_product = \intval(Tools::getValue('id_product'));
        $id_product_attribute = \intval(Tools::getValue('id_product_attribute'));
        $product_name = Tools::getValue('product_name') . ' - Format : ' . Tools::getValue('product_format');
        $product_reference = \strval(\Tools::getValue('product_reference'));
        $product_ean13 = \strval(\Tools::getValue('product_ean13'));
        $poids_net = 0;

        if ($id_product_attribute) {
            $combination = new Combination($id_product_attribute);
            /* @phpstan-ignore-next-line Attribut absent du code source */
            $poids_net = $combination->net_weight;
        } else {
            $product = new Product($id_product_attribute);
            /* @phpstan-ignore-next-line Attribut absent du code source */
            $poids_net = $product->net_weight;
        }
        $date_achat = $idOrder ? $order->invoice_date : date('Y-m-d');

        $animalSac = new AnimalSac();
        $animalSac->id_animal = (int) $animal->id;
        $animalSac->id_product = $id_product;
        $animalSac->id_product_attribute = $id_product_attribute;
        $animalSac->product_name = $product_name;
        $animalSac->product_reference = $product_reference;
        $animalSac->product_ean13 = $product_ean13;
        $animalSac->id_order = (int) $order->id;
        $animalSac->date_achat = $date_achat;
        $animalSac->poids_net = (int) round($poids_net * 1000);
        $animalSac->nombre_rations = (int) floor($animalSac->poids_net / $animal->ration);
        $animalSac->nombre_rations_biais = 0;

        $dateAchat = new DateTime($date_achat);
        $dateAchat->add(new DateInterval('P' . $animalSac->nombre_rations . 'D'));
        $animalSac->date_fin_estimee = $dateAchat->format('Y-m-d H:i:s');

        // Sauvegarde le sac associé à l'animal
        try {
            $animalSac->save();
        } catch (PrestaShopException $e) {
            var_dump($e->getMessage());
        }

        // Retourne l'animal avec ses sacs
        return $this->serializeAnimal($animal);
    }

    /**
     * Mise à jour d'un sac d'un animal.
     *
     * @return array<string, mixed>
     *
     * @throws Exception
     */
    protected function updateAnimalSac(): array
    {
        $idAnimalSac = \intval(Tools::getValue('id_animal_sac'));

        $animalSac = new AnimalSac($idAnimalSac);
        $animal = new Animal((int) $animalSac->id_animal);

        // Vérification de sécurité
        if ($animal->id_customer != $this->context->customer->id) {
            \header('HTTP/1.0 403 Forbidden');

            return [];
        }

        // Mise à jour du nombre de rations estimé
        $animalSac->nombre_rations = (int) \floor($animalSac->poids_net / $animal->ration);
        // Mise à jour du biais des rations
        $animalSac->nombre_rations_biais = \intval(\Tools::getValue('nombre_rations_biais'));
        $date_fin_estimee = \DateTime::createFromFormat('Y-m-d', $animalSac->date_achat);

        if (!$date_fin_estimee instanceof \DateTime) {
            throw new Exception('Erreur lors de la récupération de la date de fin estimée');
        }

        $date_fin_estimee->add(new DateInterval('P' . ($animalSac->nombre_rations + $animalSac->nombre_rations_biais) . 'D'));
        $animalSac->date_fin_estimee = $date_fin_estimee->format('Y-m-d');

        // Sauvegarde le sac associé à l'animal
        try {
            $animalSac->save();
        } catch (PrestaShopException $e) {
            var_dump($e->getMessage());
        }

        // Retourne l'animal avec ses sacs
        return $this->serializeAnimal($animal);
    }

    /**
     * @return array<int, array<string, mixed>>
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    protected function actionSacListAvailable(): array
    {
        $result = Db::getInstance(false)
            ->executeS(
                'SELECT o.*'
                . ' FROM `' . _DB_PREFIX_ . 'orders` o'
                . ' WHERE `o`.`id_customer` = ' . (int) $this->context->customer->id
                . ' AND `o`.`invoice_date` >= "' . date('Y-m-d', time() - 12 * 31 * 24 * 3600) . '"'
                . ' ORDER BY `o`.`invoice_date` DESC'
            );

        $orders = [];
        if (is_array($result)) {
            /** @var Order[] $orders */
            $orders = ObjectModel::hydrateCollection(
                Order::class, $result
            );
        }

        $ret = [];

        foreach ($orders as $order) {
            $productDetails = $order->getProductsDetail();

            foreach ($productDetails as $productDetail) {
                if (AnimalSac::isCroquette((int) $productDetail['product_id'])) {
                    $ret[] = [
                        'id_order' => $order->id,
                        'id_product' => $productDetail['product_id'],
                        'id_product_attribute' => $productDetail['product_attribute_id'],
                        'date_achat' => $order->invoice_date,
                        'product_name' => $productDetail['product_name'],
                        'product_reference' => $productDetail['product_reference'],
                        'product_ean13' => $productDetail['product_ean13'],
                    ];
                }
            }
        }

        return $ret;
    }

    /**
     * Assign template vars related to page content.
     *
     * @throws Exception
     *
     * @see FrontController::initContent()
     */
    public function initContent(): void
    {
        parent::initContent();

        $statusCode = null;
        $recommandationManagerApi = new RecommandationController($this->context->customer);

        try {
            switch (\strval(\Tools::getValue('action', 'nothing'))) {
                case 'create':
                    $ret = $this->actionCreate();
                    break;

                case 'cricCrocImport':
                    if ('_new' !== \strval(\Tools::getValue('idAnimal'))) {
                        $animal = new Animal(\intval(\Tools::getValue('idAnimal')));

                        if (!$animal->id) {
                            $statusCode = 404;
                            throw new Exception('L\'animal n\'existe pas');
                        }

                        if ($animal->id_customer != $this->context->customer->id) {
                            $statusCode = 401;
                            throw new Exception('L\'animal n\'appartient pas au client');
                        }
                    }

                    $handler = new RecommandationHandler($this->context->customer, $this->translator);
                    $animalId = \strval(\Tools::getValue('idAnimal'));
                    $recommandation = $handler->import(
                        \trim(\strtoupper(\strval(\Tools::getValue('code')))),
                        \is_numeric($animalId) ? (int) $animalId : null
                    );

                    $ret = $this->serializeAnimal(new Animal($recommandation->id_animal));
                    break;

                case 'cricCrocList':
                    $ret = $recommandationManagerApi->actionCricCrocList();
                    break;

                case 'cricCrocGet':
                    $recoId = \intval(\Tools::getValue('recoId'));
                    if (!$recoId) {
                        $statusCode = 400;
                        throw new Exception('La requête n\'est pas valide');
                    }

                    $ret = $recommandationManagerApi->actionCricCrocGetRecoById($recoId);
                    break;

                case 'cricCrocDelete':
                    $recommandation = new Recommandation(\intval(\Tools::getValue('idReco')));

                    if (!$recommandation->id) {
                        $statusCode = 404;
                        throw new Exception('La recommandation n\'existe pas');
                    }

                    if ($recommandation->id_customer != $this->context->customer->id) {
                        $statusCode = 401;
                        throw new Exception('La recommandation n\'appartient pas au client');
                    }

                    $ret = $recommandationManagerApi->actionCricCrocDelete($recommandation->id);
                    break;

                case 'cricCrocUpdate':
                    $recommandation = new Recommandation(\intval(\Tools::getValue('idReco')));

                    if (!$recommandation->id || $recommandation->deleted) {
                        $statusCode = 404;
                        throw new Exception('La recommandation n\'existe pas');
                    }

                    $animal = new Animal(\intval(\Tools::getValue('idAnimal')));

                    if (!$animal->id) {
                        $statusCode = 404;
                        throw new Exception('L\'animal n\'existe pas');
                    }

                    if ($animal->id_customer != $this->context->customer->id) {
                        $statusCode = 401;
                        throw new Exception('L\'animal n\'appartient pas au client');
                    }

                    $ret = $recommandationManagerApi->actionCricCrocUpdate(
                        $recommandation->id,
                        $animal->id,
                        \intval(\Tools::getValue('idProduct')),
                        \intval(\Tools::getValue('quantity'))
                    );
                    break;

                case 'recommandationPdf':
                    $recommandation = new Recommandation(\intval(\Tools::getValue('idReco')));

                    if (!$recommandation->id) {
                        $statusCode = 404;
                        throw new Exception('La recommandation n\'existe pas');
                    }

                    if ($recommandation->id_customer != $this->context->customer->id) {
                        $statusCode = 401;
                        throw new Exception('La recommandation n\'appartient pas au client');
                    }

                    $recommandationManagerApi->actionRecommandationOpenPdf($recommandation->id);
                    $ret = [];
                    break;

                case 'cricCrocCheckCodeReco':
                    $ret = $recommandationManagerApi->actionCricCrocCheckCodeReco(
                        \strval(\Tools::getValue('code'))
                    );
                    break;

                case 'delete':
                    $ret = $this->actionDelete();
                    break;

                case 'get':
                    $ret = $this->actionGet();
                    break;

                case 'list':
                    $ret = $this->actionList();
                    break;

                case 'update':
                    $ret = $this->actionUpdate();
                    break;

                case 'search_sac_detail':
                    $ret = $this->actionSearchSacDetail();
                    break;

                case 'associate':
                    $ret = $this->actionAssociate();
                    break;

                case 'sacsListAvailable':
                    $ret = $this->actionSacListAvailable();
                    break;

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

                default:
                    $ret = [];
            }

            echo \json_encode($ret, \JSON_PRETTY_PRINT);
            exit;
        } catch (PrestaShopDatabaseException $e) {
            \header('HTTP/1.0 500 Internal Server Error');
            echo \json_encode(['error' => $e->getMessage()]);
            exit;
        } catch (PrestaShopException $e) {
            \header('HTTP/1.0 500 Internal Server Error');
            echo \json_encode(['error' => $e->getMessage()]);
            exit;
        } catch (Exception $e) {
            $statusCode ? \http_response_code($statusCode) : \http_response_code(500);
            echo \json_encode(['error' => $e->getMessage()]);
            exit;
        }
    }
}
