<?php

declare(strict_types=1);

namespace Gls\GlsPoland\Controller\Admin;

use Gls\GlsPoland\AdePlus\Authorization\Fault\IncorrectCredentialsFault;
use Gls\GlsPoland\AdePlus\Authorization\Fault\SessionNotFoundFault;
use Gls\GlsPoland\AdePlus\ClientFactoryInterface;
use Gls\GlsPoland\AdePlus\Fault\AdePlusFault;
use Gls\GlsPoland\AdePlus\Services\GetAllowed;
use Gls\GlsPoland\Carrier\CarrierType;
use Gls\GlsPoland\Configuration\Api;
use Gls\GlsPoland\Configuration\Orders;
use Gls\GlsPoland\Configuration\SenderAddressConfigurationInterface;
use Gls\GlsPoland\Exception\UnableToSelectSenderAddressException;
use Gls\GlsPoland\Form\Type\ApiConfigurationType;
use Gls\GlsPoland\Form\Type\CarrierTypeChoiceType;
use Gls\GlsPoland\Form\Type\CreateCourierCarrierType;
use Gls\GlsPoland\Form\Type\CreateShopDeliveryCarrierType;
use Gls\GlsPoland\Form\Type\OrdersConfigurationType;
use Gls\GlsPoland\Form\Type\SenderDetailsType;
use Gls\GlsPoland\Message\UpdateApiConfigurationCommand;
use Gls\GlsPoland\PrestaShop\Grid\Definition\Factory\FilterableGridDefinitionFactoryInterface;
use Gls\GlsPoland\PrestaShop\Grid\Filters\CarrierFilters;
use Gls\GlsPoland\PrestaShop\Message\CreateCourierCarrierCommand;
use Gls\GlsPoland\PrestaShop\Message\CreateShopDeliveryCarrierCommand;
use Gls\GlsPoland\PrestaShop\Message\DeleteCarrierCommand;
use Gls\GlsPoland\Translation\TranslatorAwareTrait;
use PrestaShop\PrestaShop\Core\CommandBus\CommandBusInterface;
use PrestaShop\PrestaShop\Core\Grid\Filter\GridFilterFormFactoryInterface;
use PrestaShop\PrestaShop\Core\Grid\GridFactoryInterface;
use PrestaShop\PrestaShop\Core\Grid\Presenter\GridPresenterInterface;
use PrestaShopBundle\Security\Annotation\AdminSecurity;
use PrestaShopBundle\Security\Voter\PageVoter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\DBAL\Exception\TableNotFoundException;

/**
 * @Route(path="config", name="admin_gls_poland_config_", defaults={"_legacy_controller"=ConfigurationController::TAB_NAME, "_legacy_link"=ConfigurationController::TAB_NAME})
 */
final class ConfigurationController extends AbstractController
{
    use TranslatorAwareTrait;

    public const TAB_NAME = 'AdminGlsPolandConfiguration';
    public const CARRIERS_TAB_NAME = 'AdminCarriers';

    public static function getSubscribedServices(): array
    {
        return parent::getSubscribedServices() + [
            '?' . Api\PersistentConfigurationInterface::class,
        ];
    }

    /**
     * @Route(path="/api", name="api", methods={"GET", "POST"})
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller')) || is_granted('read', 'AdminModules')", redirectRoute="admin_module_manage")
     */
    public function apiConfig(Request $request, Api\PersistentConfigurationInterface $configuration, CommandBusInterface $bus, ClientFactoryInterface $clientFactory): Response
    {
        $this->initConfig();

        $form = $this->createForm(ApiConfigurationType::class, $configuration->asNonPersistent(), [
            'disabled' => !$canUpdate = $this->canUpdateConfiguration(),
            'validation_groups' => $this->isApiConnectionTestRequest($request) ? ['Default', 'Api'] : ['Default'],
        ]);

        if ($canUpdate && $form->handleRequest($request) && $form->isSubmitted() && $form->isValid()) {
            /** @var Api\ConfigurationInterface $formData */
            $formData = $form->getData();

            if ($this->isApiConnectionTestRequest($request)) {
                $this->testApiConnection($formData, $clientFactory);

                return $this->redirectToRoute('admin_gls_poland_config_api');
            }

            $bus->handle(new UpdateApiConfigurationCommand($formData));
            $this->addFlash('success', $this->getTranslator()->trans('Successful update.', [], 'Admin.Notifications.Success'));

            return $this->redirectToRoute('admin_gls_poland_config_api');
        }



        return $this->render('@Modules/glspoland/views/templates/admin/config/api.html.twig', [
            'form' => $form->createView(),
            'can_update' => $canUpdate,
            'layoutTitle' => $this->getTranslator()->trans('API configuration', [], 'Modules.Glspoland.Configuration'),
            'headerTabContent' => $this->renderNav('api'),
            'nav_items' => $this->getNavItems('api'),
            'layoutHeaderToolbarBtn' => $this->getToolbarButtons(),
        ]);
    }

    /**
     * @Route(path="/sender-details", name="sender_details", methods={"GET", "POST"})
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller')) || is_granted('read', 'AdminModules')", redirectRoute="admin_module_manage")
     */
    public function senderDetailsConfig(Request $request, SenderAddressConfigurationInterface $configuration): Response
    {
        $this->initConfig();

        if (!$this->hasApiCredentials()) {
            $this->addFlash('warning', $this->getTranslator()->trans('API credentials are missing or invalid. Please update the API configuration before accessing the sender details configuration page.', [], 'Modules.Glspoland.Configuration'));

            return $this->redirectToRoute('admin_gls_poland_config_api');
        }

        try {
            $form = $this->createForm(SenderDetailsType::class, $configuration->getSenderAddressDetails(), [
                'disabled' => !$canUpdate = $this->canUpdateConfiguration(),
            ]);
        } catch (IncorrectCredentialsFault|SessionNotFoundFault $e) {
            $this->addFlash('warning', $this->getTranslator()->trans('API credentials are missing or invalid. Please update the API configuration before accessing the sender details configuration page.', [], 'Modules.Glspoland.Configuration'));

            return $this->redirectToRoute('admin_gls_poland_config_api');
        } catch (UnableToSelectSenderAddressException $e) {
            $this->addFlash('warning', $this->getTranslator()->trans('Selecting a sender address is not allowed for the configured API account.', [], 'Modules.Glspoland.Configuration'));
            $configuration->setSenderAddressDetails(null);

            return $this->render('@PrestaShop/Admin/layout.html.twig', [
                'layoutTitle' => $this->getTranslator()->trans('Sender details configuration', [], 'Modules.Glspoland.Configuration'),
                'headerTabContent' => $this->renderNav('sender_details'),
                'nav_items' => $this->getNavItems('sender_details'),
                'layoutHeaderToolbarBtn' => $this->getToolbarButtons(),
            ]);
        }

        if ($canUpdate && $form->handleRequest($request) && $form->isSubmitted() && $form->isValid()) {
            $configuration->setSenderAddressDetails($form->getData());
            $this->addFlash('success', $this->getTranslator()->trans('Successful update.', [], 'Admin.Notifications.Success'));

            return $this->redirectToRoute('admin_gls_poland_config_sender_details');
        }

        return $this->render('@Modules/glspoland/views/templates/admin/config/config_form.html.twig', [
            'form' => $form->createView(),
            'can_update' => $canUpdate,
            'layoutTitle' => $this->getTranslator()->trans('Sender details configuration', [], 'Modules.Glspoland.Configuration'),
            'headerTabContent' => $this->renderNav('sender_details'),
            'nav_items' => $this->getNavItems('sender_details'),
            'layoutHeaderToolbarBtn' => $this->getToolbarButtons(),
        ]);
    }

    /**
     * @Route(path="/orders", name="orders", methods={"GET", "POST"})
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller')) || is_granted('read', 'AdminModules')", redirectRoute="admin_module_manage")
     */
    public function ordersConfig(Request $request, Orders\PersistentConfigurationInterface $configuration): Response
    {
        $this->initConfig();

        $form = $this->createForm(OrdersConfigurationType::class, $configuration->asNonPersistent(), [
            'disabled' => !$canUpdate = $this->canUpdateConfiguration(),
        ]);

        if ($canUpdate && $form->handleRequest($request) && $form->isSubmitted() && $form->isValid()) {
            $configuration->save($form->getData());
            $this->addFlash('success', $this->getTranslator()->trans('Successful update.', [], 'Admin.Notifications.Success'));

            return $this->redirectToRoute('admin_gls_poland_config_orders');
        }

        return $this->render('@Modules/glspoland/views/templates/admin/config/config_form.html.twig', [
            'form' => $form->createView(),
            'can_update' => $canUpdate,
            'layoutTitle' => $this->getTranslator()->trans('Orders configuration', [], 'Modules.Glspoland.Configuration'),
            'headerTabContent' => $this->renderNav('orders'),
            'nav_items' => $this->getNavItems('orders'),
            'layoutHeaderToolbarBtn' => $this->getToolbarButtons(),
        ]);
    }

    /**
     * @Route(path="/download/{name}", name="pdf_download", methods={"GET"}, requirements={"name"="[a-zA-Z_]+"})
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller')) || is_granted('read', 'AdminModules')", redirectRoute="admin_module_manage")
     */
    public function downloadPdf(string $name, \Module $module): BinaryFileResponse
    {
        try {
            $file = new File(sprintf('%s/docs/%s.pdf', rtrim($module->getLocalPath(), '/'), $name));
        } catch (FileNotFoundException $e) {
            throw new NotFoundHttpException('File does not exist', $e);
        }

        $response = $this->file($file);
        $response->headers->set('Content-Type', 'application/pdf');

        return $response;
    }

    /**
     * @Route(path="/carriers", name="carriers_index", methods={"GET"})
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller')) || is_granted('read', 'AdminModules')", redirectRoute="admin_module_manage")
     */
    public function carriers(CarrierFilters $filters, GridFactoryInterface $gridFactory, GridPresenterInterface $gridPresenter): Response
    {
        $this->initConfig();

        try {
            $grid = $gridFactory->getGrid($filters);
        } catch (TableNotFoundException $e) {
            $this->ensureDatabaseSchema();
            $grid = $gridFactory->getGrid($filters);
        }

        return $this->render('@Modules/glspoland/views/templates/admin/config/carriers.html.twig', [
            'grid' => $gridPresenter->present($grid),
            'layoutTitle' => $this->getTranslator()->trans('Carriers', [], 'Modules.Glspoland.Configuration'),
            'headerTabContent' => $this->renderNav('carriers'),
            'nav_items' => $this->getNavItems('carriers'),
            'layoutHeaderToolbarBtn' => $this->getCarrierToolbarButtons(),
            'carrier_type_form' => $this->createCarrierTypeChoiceForm()->createView(),
        ]);
    }

    /**
     * @Route("/carriers", name="carriers_filter", methods={"POST"})
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller')) || is_granted('read', 'AdminModules')", redirectRoute="admin_module_manage")
     */
    public function filterCarriers(Request $request, FilterableGridDefinitionFactoryInterface $gridDefinitionFactory, GridFilterFormFactoryInterface $filterFormFactory): Response
    {
        $gridDefinition = $gridDefinitionFactory->getDefinition();
        $filtersForm = $filterFormFactory
            ->create($gridDefinition)
            ->handleRequest($request);

        $redirectParams = [];
        if ($filtersForm->isSubmitted()) {
            $redirectParams[$gridDefinitionFactory->getFilterId()] = [
                'filters' => $filtersForm->getData(),
            ];
        }

        return $this->redirectToRoute('admin_gls_poland_config_carriers_index', $redirectParams, Response::HTTP_SEE_OTHER);
    }

    /**
     * @Route(path="/carriers/new/courier", name="carriers_create_courier", methods={"GET","POST"})
     * @AdminSecurity("is_granted('create', 'AdminCarriers') || is_granted('update', 'AdminModules')", redirectRoute="admin_gls_poland_config_carriers_index")
     */
    public function createStandardCarrier(Request $request, CommandBusInterface $bus): Response
    {
        $this->initConfig();

        $command = new CreateCourierCarrierCommand($this->getTranslator()->trans('GLS Courier', [], 'Modules.Glspoland.Carrier'), ['PL']);
        $form = $this
            ->createForm(CreateCourierCarrierType::class, $command)
            ->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $bus->handle($form->getData());
            $this->addFlash('success', $this->getTranslator()->trans('Successful creation', [], 'Admin.Notifications.Success'));

            return $this->redirectToRoute('admin_gls_poland_config_carriers_index');
        }

        return $this->render('@Modules/glspoland/views/templates/admin/config/courier_carrier_form.html.twig', [
            'form' => $form->createView(),
            'layoutTitle' => $this->getTranslator()->trans('New courier carrier', [], 'Modules.Glspoland.Configuration'),
            'headerTabContent' => $this->renderNav('carriers'),
            'nav_items' => $this->getNavItems('carriers'),
            'layoutHeaderToolbarBtn' => $this->getToolbarButtons(),
        ]);
    }

    /**
     * @Route(path="/carriers/new/sds", name="carriers_create_sds", methods={"GET","POST"})
     * @AdminSecurity("is_granted('create', 'AdminCarriers') || is_granted('update', 'AdminModules')", redirectRoute="admin_gls_poland_config_carriers_index")
     */
    public function createShopDeliveryCarrier(Request $request, CommandBusInterface $bus): Response
    {
        $this->initConfig();

        $command = new CreateShopDeliveryCarrierCommand($this->getTranslator()->trans('GLS ParcelShop', [], 'Modules.Glspoland.Carrier'), ['PL']);
        $form = $this
            ->createForm(CreateShopDeliveryCarrierType::class, $command)
            ->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $bus->handle($form->getData());
            $this->addFlash('success', $this->getTranslator()->trans('Successful creation', [], 'Admin.Notifications.Success'));

            return $this->redirectToRoute('admin_gls_poland_config_carriers_index');
        }

        return $this->render('@Modules/glspoland/views/templates/admin/config/carrier_form.html.twig', [
            'form' => $form->createView(),
            'layoutTitle' => $this->getTranslator()->trans('New parcel shop delivery carrier', [], 'Modules.Glspoland.Configuration'),
            'headerTabContent' => $this->renderNav('carriers'),
            'nav_items' => $this->getNavItems('carriers'),
            'layoutHeaderToolbarBtn' => $this->getToolbarButtons(),
        ]);
    }

    /**
     * @Route("/carriers/{id}/delete", name="carriers_delete", methods={"POST"}, requirements={"id"="\d+"})
     * @AdminSecurity("is_granted('delete', 'AdminGlsPolandConfiguration') || is_granted('update', 'AdminModules')", redirectRoute="admin_gls_poland_config_carriers_index")
     */
    public function deleteCarrier(int $id, CommandBusInterface $bus): Response
    {
        $this->initConfig();

        $bus->handle(new DeleteCarrierCommand($id));
        $this->addFlash('success', $this->getTranslator()->trans('Successful deletion', [], 'Admin.Notifications.Success'));

        return $this->redirectToRoute('admin_gls_poland_config_carriers_index', [], Response::HTTP_SEE_OTHER);
    }

    private function getCarrierToolbarButtons(): array
    {
        if (!$this->isGranted(PageVoter::CREATE, self::CARRIERS_TAB_NAME)) {
            return $this->getToolbarButtons();
        }

        return array_merge([
            'new_carrier' => [
                'modal_target' => '#new_carrier_modal',
                'href' => $this->generateUrl('admin_gls_poland_config_carriers_create_courier'),
                'desc' => $this->getTranslator()->trans('New carrier', [], 'Modules.Glspoland.Configuration'),
                'icon' => 'add_circle_outline',
            ],
        ], $this->getToolbarButtons());
    }

    private function getToolbarButtons(): array
    {
        return [
            'docs' => [
                'href' => $this->generateUrl('admin_gls_poland_config_pdf_download', [
                    'name' => 'documentation',
                ]),
                'desc' => $this->getTranslator()->trans('Download documentation', [], 'Modules.Glspoland.Configuration'),
                'icon' => 'article',
            ],
            'user_guidelines' => [
                'href' => $this->generateUrl('admin_gls_poland_config_pdf_download', [
                    'name' => 'user_guidelines',
                ]),
                'desc' => $this->getTranslator()->trans('Download user guidelines', [], 'Modules.Glspoland.Configuration'),
                'icon' => 'article',
            ],
        ];
    }

    private function renderNav(string $activeTab): string
    {
        return $this->renderView('@Modules/glspoland/views/templates/admin/config/nav.html.twig', [
            'nav_items' => $this->getNavItems($activeTab),
            'display' => 'header',
        ]);
    }

    private function getNavItems(string $activeTab): array
    {
        return [
            'api' => [
                'url' => $this->generateUrl('admin_gls_poland_config_api'),
                'label' => $this->getTranslator()->trans('API', [], 'Modules.Glspoland.Configuration'),
                'active' => 'api' === $activeTab,
            ],
            'sender_details' => [
                'url' => $this->generateUrl('admin_gls_poland_config_sender_details'),
                'label' => $this->getTranslator()->trans('Sender details', [], 'Modules.Glspoland.Configuration'),
                'active' => 'sender_details' === $activeTab,
            ],
            'carriers' => [
                'url' => $this->generateUrl('admin_gls_poland_config_carriers_index'),
                'label' => $this->getTranslator()->trans('Carriers', [], 'Modules.Glspoland.Configuration'),
                'active' => 'carriers' === $activeTab,
            ],
            'orders' => [
                'url' => $this->generateUrl('admin_gls_poland_config_orders'),
                'label' => $this->getTranslator()->trans('Orders', [], 'Modules.Glspoland.Configuration'),
                'active' => 'orders' === $activeTab,
            ],
        ];
    }

    private function createCarrierTypeChoiceForm(): FormInterface
    {
        return $this->createForm(CarrierTypeChoiceType::class, null, [
            'choice_attr' => function ($choice, $key, $value): array {
                $url = CarrierType::SHOP_DELIVERY === $value
                    ? $this->generateUrl('admin_gls_poland_config_carriers_create_sds')
                    : $this->generateUrl('admin_gls_poland_config_carriers_create_courier');

                return ['data-url' => $url];
            },
            'label' => $this->getTranslator()->trans('Carrier type', [], 'Modules.Glspoland.Carrier'),
        ]);
    }

        private function isApiConnectionTestRequest(Request $request): bool
    {
        return '1' === (string) $request->request->get('test_connection');
    }

    private function testApiConnection(Api\ConfigurationInterface $configuration, ClientFactoryInterface $clientFactory): void
    {
        $sandbox = $configuration->isSandboxEnabled();
        $credentials = $sandbox
            ? $configuration->getTestCredentials()
            : $configuration->getProdCredentials();

        if (null === $credentials) {
            $this->addFlash('warning', $this->getTranslator()->trans('No API credentials set for selected mode.', [], 'Modules.Glspoland.Configuration'));

            return;
        }

        try {
            $client = $clientFactory->create($sandbox, $credentials);
            $client->servicesGetAllowed(new GetAllowed());

            $this->addFlash('success', $this->getTranslator()->trans('Connection test successful.', [], 'Modules.Glspoland.Configuration'));
        } catch (AdePlusFault $e) {
            $this->addFlash('error', $this->getTranslator()->trans('Connection test failed: {error}', [
                '{error}' => $e->getMessage(),
            ], 'Modules.Glspoland.Configuration'));
        } catch (\Throwable $e) {
            $this->addFlash('error', $this->getTranslator()->trans('Connection test failed: {error}', [
                '{error}' => $e->getMessage(),
            ], 'Modules.Glspoland.Configuration'));
        }
    }

    private function hasApiCredentials(): bool
    {
        if (null === $this->container) {
            return true; // keep BC for environments without container access
        }

        try {
            $configuration = $this->container->get(Api\PersistentConfigurationInterface::class);
        } catch (ServiceNotFoundException $e) {
            return true; // keep BC for environments without this service
        }

        return null !== $configuration->getCredentials();
    }

    /**
     * If the module is disabled, calls the hook that initializes framework config.
     * This allows the config page to be accessible on PS 1.7.x.
     */
    private function initConfig(): void
    {
        /** @var \GlsPoland|false $module */
        $module = \Module::getInstanceByName('glspoland');

        if (false === $module) {
            return;
        }

        $module->hookActionDispatcherBefore([
            'controller_type' => \Dispatcher::FC_ADMIN,
        ]);
    }

    private function canUpdateConfiguration(): bool
    {
        return $this->isGranted(PageVoter::UPDATE, self::TAB_NAME)
            || $this->isGranted(PageVoter::UPDATE, 'AdminModules');
    }

    private function ensureDatabaseSchema(): void
    {
        $db = \Db::getInstance();
        $prefix = _DB_PREFIX_;
        $engine = defined('_MYSQL_ENGINE_') ? _MYSQL_ENGINE_ : 'InnoDB';

        $queries = [
            sprintf(
                'CREATE TABLE IF NOT EXISTS `%sgls_poland_carrier` (
                    `id_reference` INT(10) UNSIGNED NOT NULL,
                    `type` VARCHAR(32) NOT NULL,
                    `countries` TEXT NOT NULL,
                    `parcelshop_type` VARCHAR(16) NULL DEFAULT NULL,
                    `cash_on_delivery` TINYINT(1) NULL DEFAULT NULL,
                    `saturday_delivery` TINYINT(1) NULL DEFAULT NULL,
                    `delivery_before_10` TINYINT(1) NULL DEFAULT NULL,
                    `delivery_before_12` TINYINT(1) NULL DEFAULT NULL,
                    `document_return` TINYINT(1) NULL DEFAULT NULL,
                    PRIMARY KEY (`id_reference`)
                ) ENGINE=%s DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;',
                $prefix,
                $engine
            ),
            sprintf(
                'CREATE TABLE IF NOT EXISTS `%sgls_poland_consignment` (
                    `id` INT NOT NULL AUTO_INCREMENT,
                    `prep_box_id` INT NOT NULL,
                    `id_order` INT(10) UNSIGNED NOT NULL,
                    `pickup_id` INT NULL DEFAULT NULL,
                    `consignment_id` INT NULL DEFAULT NULL,
                    `sandbox` TINYINT(1) NOT NULL,
                    `reference` VARCHAR(25) NULL DEFAULT NULL,
                    `email` VARCHAR(40) NULL DEFAULT NULL,
                    `phone` VARCHAR(40) NULL DEFAULT NULL,
                    `created_at` DATETIME NOT NULL,
                    PRIMARY KEY (`id`),
                    INDEX `idx_gls_poland_consignment_order` (`id_order`)
                ) ENGINE=%s DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;',
                $prefix,
                $engine
            ),
            sprintf(
                'CREATE TABLE IF NOT EXISTS `%sgls_poland_parcel` (
                    `id` INT NOT NULL AUTO_INCREMENT,
                    `consignment_id` INT NOT NULL,
                    `weight` DOUBLE PRECISION NOT NULL,
                    `reference` VARCHAR(25) NULL DEFAULT NULL,
                    `number` VARCHAR(11) NULL DEFAULT NULL,
                    PRIMARY KEY (`id`),
                    INDEX `idx_gls_poland_parcel_consignment` (`consignment_id`)
                ) ENGINE=%s DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;',
                $prefix,
                $engine
            ),
            sprintf(
                'CREATE TABLE IF NOT EXISTS `%sgls_poland_checkout_session` (
                    `id_cart` INT(10) UNSIGNED NOT NULL,
                    `parcel_shops` LONGTEXT NOT NULL,
                    PRIMARY KEY (`id_cart`)
                ) ENGINE=%s DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;',
                $prefix,
                $engine
            ),
            sprintf(
                'CREATE TABLE IF NOT EXISTS `%sgls_poland_order_parcel_shop` (
                    `id_order` INT(10) UNSIGNED NOT NULL,
                    `parcel_shop_id` VARCHAR(32) NOT NULL,
                    `name` VARCHAR(255) NOT NULL,
                    `street` VARCHAR(255) NULL DEFAULT NULL,
                    `postal_code` VARCHAR(32) NULL DEFAULT NULL,
                    `city` VARCHAR(128) NULL DEFAULT NULL,
                    PRIMARY KEY (`id_order`)
                ) ENGINE=%s DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;',
                $prefix,
                $engine
            ),
        ];

        foreach ($queries as $sql) {
            $db->execute($sql);
        }

        $carrierTable = $prefix . 'gls_poland_carrier';
        $parcelShopTypeColumn = (bool) $db->getValue(sprintf(
            "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '%s' AND COLUMN_NAME = 'parcelshop_type'",
            pSQL($carrierTable)
        ));

        if (!$parcelShopTypeColumn) {
            $db->execute(sprintf(
                'ALTER TABLE `%sgls_poland_carrier` ADD `parcelshop_type` VARCHAR(16) NULL DEFAULT NULL AFTER `countries`',
                $prefix
            ));
        }

        // Mark schema as at least baseline to avoid repeated repair attempts.
        \Configuration::updateValue('GLS_POLAND_DB_SCHEMA_VERSION', '1.2.0');
    }
}
