<?php

declare(strict_types=1);

namespace Gls\GlsPoland\PrestaShop\Order;

use Gls\GlsPoland\DataProvider\ParcelShopDataProvider;
use Gls\GlsPoland\Entity\OrderParcelShop;
use Gls\GlsPoland\Entity\ShopDeliveryCarrier;
use Gls\GlsPoland\PrestaShop\Helper\CarrierFinder;
use Gls\GlsPoland\Repository\CheckoutSessionRepository;
use Gls\GlsPoland\Repository\OrderParcelShopRepository;

final class OrderParcelShopPersister
{
    private $carrierFinder;
    private $checkoutSessionRepository;
    private $orderParcelShopRepository;
    private $parcelShopDataProvider;

    public function __construct(
        CarrierFinder $carrierFinder,
        CheckoutSessionRepository $checkoutSessionRepository,
        OrderParcelShopRepository $orderParcelShopRepository,
        ParcelShopDataProvider $parcelShopDataProvider
    ) {
        $this->carrierFinder = $carrierFinder;
        $this->checkoutSessionRepository = $checkoutSessionRepository;
        $this->orderParcelShopRepository = $orderParcelShopRepository;
        $this->parcelShopDataProvider = $parcelShopDataProvider;
    }

    public function persistForOrder(\Order $order): void
    {
        if (!\Validate::isLoadedObject($order)) {
            return;
        }

        $carrier = $this->carrierFinder->findOneByCarrierId((int) $order->id_carrier);
        if (!$carrier instanceof ShopDeliveryCarrier) {
            return;
        }

        $checkoutSession = $this->checkoutSessionRepository->find((int) $order->id_cart);
        $parcelShopId = $this->resolveParcelShopId($checkoutSession, $carrier, $order);
        if (null === $parcelShopId) {
            return;
        }

        $parcelShop = $this->parcelShopDataProvider->getParcelShop($parcelShopId);
        if (null === $parcelShop) {
            return;
        }

        $entity = $this->orderParcelShopRepository->find((int) $order->id);
        if ($entity instanceof OrderParcelShop) {
            $entity->updateFromParcelShop($parcelShop);
        } else {
            $entity = new OrderParcelShop((int) $order->id, $parcelShop);
        }

        $this->orderParcelShopRepository->add($entity);
    }

    private function resolveParcelShopId(?\Gls\GlsPoland\Entity\CheckoutSession $checkoutSession, ShopDeliveryCarrier $carrier, \Order $order): ?string
    {
        if (null !== $checkoutSession) {
            $parcelShopId = $checkoutSession->getParcelShopId($carrier->getId()->getValue());
            if (null === $parcelShopId) {
                $parcelShopId = $checkoutSession->getParcelShopId((int) $order->id_carrier);
            }

            if (null !== $parcelShopId && '' !== trim((string) $parcelShopId)) {
                return (string) $parcelShopId;
            }
        }

        return $this->resolveParcelShopIdFromCookie($carrier, $order);
    }

    private function resolveParcelShopIdFromCookie(ShopDeliveryCarrier $carrier, \Order $order): ?string
    {
        $context = \Context::getContext();
        if (!isset($context->cookie) || !isset($context->cookie->gls_poland_last_selection)) {
            return null;
        }

        $data = json_decode((string) $context->cookie->gls_poland_last_selection, true);
        if (!is_array($data)) {
            return null;
        }

        $parcelShopId = isset($data['parcelShopId']) ? trim((string) $data['parcelShopId']) : '';
        if ('' === $parcelShopId) {
            return null;
        }

        $timestamp = isset($data['ts']) ? (int) $data['ts'] : 0;
        if (0 < $timestamp && (time() - $timestamp) > 3600) {
            return null;
        }

        $carrierReferenceId = isset($data['carrierReferenceId']) ? (int) $data['carrierReferenceId'] : 0;
        $orderCarrierId = isset($order->id_carrier) ? (int) $order->id_carrier : 0;
        $carrierId = $carrier->getId()->getValue();

        if (
            0 < $carrierReferenceId
            && $carrierReferenceId !== $carrierId
            && $carrierReferenceId !== $orderCarrierId
        ) {
            return null;
        }

        $selectedCartId = isset($data['cartId']) ? (int) $data['cartId'] : 0;
        $orderCartId = isset($order->id_cart) ? (int) $order->id_cart : 0;
        if (0 < $selectedCartId && 0 < $orderCartId && $selectedCartId !== $orderCartId) {
            if ($selectedCartId !== ($orderCartId + 1) && $selectedCartId !== ($orderCartId - 1)) {
                return null;
            }
        }

        return $parcelShopId;
    }
}
