<?php

declare(strict_types=1);

namespace Gls\GlsPoland\PrestaShop\Checkout\Module;

use Gls\GlsPoland\PrestaShop\Asset\DTO\Assets;
use Gls\GlsPoland\PrestaShop\Checkout\AbstractCheckout;
use Gls\GlsPoland\PrestaShop\Checkout\Event\CarrierProcessEvent;
use Gls\GlsPoland\PrestaShop\Checkout\Exception\AbortCheckoutException;
use Gls\GlsPoland\PrestaShop\Checkout\ModuleCheckoutInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

final class SuperCheckout extends AbstractCheckout implements ModuleCheckoutInterface
{
    use ModuleControllerCheckerTrait;

    private const MODULE_NAME = 'supercheckout';
    private const CREATE_ORDER_PARAM = 'supercheckoutPlaceOrder';

    private $errors = [];

    public static function getModuleName(): string
    {
        return self::MODULE_NAME;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            CarrierProcessEvent::class => 'onCarrierProcess',
        ];
    }

    /**
     * Past version of the SuperCheckout module used to unset {@see $_POST} superglobal and did not process carrier data
     * when placing the order unless a {@see \Tools::getIsset()} condition was met for the key "delivery_option".
     *
     * @see \SupercheckoutCore::confirmOrder()
     */
    public static function fixRequestParameters(Request $request): void
    {
        if (!$request->request->has(self::CREATE_ORDER_PARAM)) {
            return;
        }

        if (null === $deliveryOption = $request->request->get('delivery_option')) {
            return;
        }

        $_GET['delivery_option'] = $deliveryOption;
    }

    public function getAssets(\Cart $cart): Assets
    {
        return parent::getAssets($cart)
            ->addJavaScript('js/front/super-checkout.js');
    }

    public function onCarrierProcess(CarrierProcessEvent $event): void
    {
        $request = $event->getRequest();

        if (!$request->request->has(self::CREATE_ORDER_PARAM)) {
            return;
        }

        $cart = $event->getCart();
        $params = $request->request->all();

        if (!$this->validateDeliveryOption($cart, $params)) {
            $deliveryOption = $params['delivery_option'] ?? [];
            $carrierIds = $this->getCarrierIdsFromDeliveryOption($cart, is_array($deliveryOption) ? $deliveryOption : []);

            self::abortCheckout(current($this->errors), $carrierIds);
        }

        $this->saveDeliveryOption($cart, $request);
    }

    protected function addError(string $error): void
    {
        $this->errors[] = $error;
    }

    /**
     * @return never-returns
     */
    private static function abortCheckout(string $error, array $carrierIds): void
    {
        $data = [
            'error' => [
                'checkout_option' => [
                    [
                        'key' => $carrierIds ? sprintf('gls_poland[%d][parcel_shop_id]', current($carrierIds)) : 'shipping_method_error',
                        'error' => $error,
                    ],
                ],
            ],
        ];

        throw AbortCheckoutException::json($data, Response::HTTP_OK);
    }

    private static function getCheckoutControllerNames(): array
    {
        return ['supercheckout', 'order'];
    }
}
