<?php

declare(strict_types=1);

namespace Gls\GlsPoland\PrestaShop\Hook\Front\Checkout;

use Gls\GlsPoland\PrestaShop\Checkout\CheckoutResolverInterface;
use Gls\GlsPoland\PrestaShop\Checkout\ModuleCheckoutInterface;
use Gls\GlsPoland\Carrier\CarrierId;
use Gls\GlsPoland\Country\IsoCode;
use Gls\GlsPoland\Entity\ShopDeliveryCarrier;
use Gls\GlsPoland\PrestaShop\Helper\CarrierFinder;
use Gls\GlsPoland\PrestaShop\Hook\HookInterface;
use Gls\GlsPoland\PrestaShop\ObjectModel\Repository\CarrierRepository as ObjectModelCarrierRepository;
use Gls\GlsPoland\Repository\CarrierRepository as ModuleCarrierRepository;
use Symfony\Component\HttpFoundation\Request;

/**
 * @deprecated use {@see DisplayBeforeBodyClosingTag} instead
 */
final class DisplayAfterCarrier implements HookInterface
{
    public const HOOK_NAME = 'displayAfterCarrier';

    private $checkoutResolver;
    private $carrierFinder;
    private $objectModelCarrierRepository;
    private $moduleCarrierRepository;

    public function __construct(
        CheckoutResolverInterface $checkoutResolver,
        CarrierFinder $carrierFinder,
        ObjectModelCarrierRepository $objectModelCarrierRepository,
        ModuleCarrierRepository $moduleCarrierRepository
    )
    {
        $this->checkoutResolver = $checkoutResolver;
        $this->carrierFinder = $carrierFinder;
        $this->objectModelCarrierRepository = $objectModelCarrierRepository;
        $this->moduleCarrierRepository = $moduleCarrierRepository;
    }

    /**
     * @param array{request?: Request, cart?: \Cart} $parameters
     */
    public function execute(array $parameters): string
    {
        $request = $parameters['request'] ?? null;
        if (null === $checkout = $this->checkoutResolver->resolve($request instanceof Request ? $request : null)) {
            return '';
        }

        if ($checkout instanceof ModuleCheckoutInterface || ($request instanceof Request && $request->attributes->getBoolean('gls_poland_carrier_extra_rendered'))) {
            return '';
        }

        $output = '';
        $cart = $parameters['cart'] ?? (\Context::getContext()->cart ?? null);

        if ($cart instanceof \Cart && 0 < (int) $cart->id_carrier) {
            $carrierId = (int) $cart->id_carrier;
            $carrier = $this->carrierFinder->findOneByCarrierId($carrierId);
            if (null === $carrier) {
                $carrier = $this->createFallbackParcelShopCarrier($carrierId);
            }

            if (null !== $carrier) {
                $output .= $checkout->renderDeliveryOptionsForm($carrier, $cart, $carrierId);
                if ($request instanceof Request && '' !== $output) {
                    $request->attributes->set('gls_poland_carrier_extra_rendered', true);
                }
            }
        }

        if ($request instanceof Request && $request->attributes->getBoolean('gls_poland_map_modal_rendered')) {
            return $output;
        }

        $output .= $checkout->renderMapModal();
        if ($request instanceof Request) {
            $request->attributes->set('gls_poland_map_modal_rendered', true);
        }

        return $output;
    }

    private function createFallbackParcelShopCarrier(int $carrierId): ?ShopDeliveryCarrier
    {
        $carrier = $this->objectModelCarrierRepository->find($carrierId);
        if (
            !$carrier instanceof \Carrier
            || 0 >= (int) $carrier->id_reference
        ) {
            return null;
        }

        $referenceId = (int) $carrier->id_reference;
        $moduleCarrier = $this->moduleCarrierRepository->find($referenceId);
        if ($moduleCarrier instanceof ShopDeliveryCarrier) {
            return $moduleCarrier;
        }

        if ('glspoland' === (string) $carrier->external_module_name) {
            return new ShopDeliveryCarrier(
                CarrierId::from($referenceId),
                IsoCode::from('PL')
            );
        }

        $normalizedName = \Tools::strtolower(trim((string) $carrier->name));
        if (
            false !== strpos($normalizedName, 'gls')
            && (
                false !== strpos($normalizedName, 'parcelshop')
                || false !== strpos($normalizedName, 'parcel shop')
                || false !== strpos($normalizedName, 'punkt odbioru')
            )
        ) {
            return new ShopDeliveryCarrier(
                CarrierId::from($referenceId),
                IsoCode::from('PL')
            );
        }

        return null;
    }
}
