<?php

declare(strict_types=1);

namespace Gls\GlsPoland\PrestaShop\Checkout\Module;

use Gls\GlsPoland\Entity\ShopDeliveryCarrier;
use Gls\GlsPoland\PrestaShop\Asset\DTO\Assets;
use Gls\GlsPoland\PrestaShop\Checkout\CarriersByDeliveryOptionFinderTrait;
use Gls\GlsPoland\PrestaShop\Checkout\CheckoutTrait;
use Gls\GlsPoland\PrestaShop\Checkout\DeliveryOptionValidatorInterface;
use Gls\GlsPoland\PrestaShop\Checkout\Event\ValidateStepCompleteEvent;
use Gls\GlsPoland\PrestaShop\Checkout\ModuleCheckoutInterface;
use Gls\GlsPoland\PrestaShop\Checkout\Presenter\CheckoutConfigPresenter;
use Gls\GlsPoland\PrestaShop\Helper\CarrierFinder;
use Gls\GlsPoland\PrestaShop\Templating\RendererInterface;
use Gls\GlsPoland\Repository\CheckoutSessionRepository;

final class TheCheckout implements ModuleCheckoutInterface
{
    use CarriersByDeliveryOptionFinderTrait;
    use CheckoutTrait {
        CheckoutTrait::getAssets as getCommonAssets;
    }
    use ModuleControllerCheckerTrait;

    private const MODULE_NAME = 'thecheckout';

    /**
     * @var CheckoutSessionRepository
     */
    private $repository;
    /**
     * @var DeliveryOptionValidatorInterface
     */
    private $validator;

    public function __construct(RendererInterface $renderer, CheckoutConfigPresenter $dataPresenter, CarrierFinder $carrierFinder, CheckoutSessionRepository $repository, DeliveryOptionValidatorInterface $validator)
    {
        $this->renderer = $renderer;
        $this->dataPresenter = $dataPresenter;
        $this->carrierFinder = $carrierFinder;
        $this->repository = $repository;
        $this->validator = $validator;
    }

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

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

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

    public function onValidateStepComplete(ValidateStepCompleteEvent $event): void
    {
        $cart = $event->getCart();
        $deliveryOption = $cart->getDeliveryOption();

        if ([] === $carriers = $this->getCarriersByDeliveryOption($cart, $deliveryOption)) {
            return;
        }

        foreach ($carriers as $carrier) {
            if (!$carrier instanceof ShopDeliveryCarrier) {
                continue;
            }

            if ($this->isValidParcelShopSelected($carrier, (int) $cart->id)) {
                continue;
            }

            $this->addError($this->getTranslator()->trans('Please select a ParcelShop.', [], 'Modules.Glspoland.Checkout'));
            $event->setComplete(false);

            return;
        }
    }

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

    private function isValidParcelShopSelected(ShopDeliveryCarrier $carrier, int $cartId): bool
    {
        $session = $this->repository->find($cartId);
        if (null === $session) {
            return false;
        }

        $parcelShopId = $session->getParcelShopId($carrier->getId()->getValue());
        if (null === $parcelShopId) {
            return false;
        }

        $violations = $this->validator->validate($carrier, [
            'parcel_shop_id' => $parcelShopId,
        ]);

        return 0 === count($violations);
    }
}
