<?php

declare(strict_types=1);

namespace Gls\GlsPoland\PrestaShop\Order;

use Gls\GlsPoland\Consignment\DTO\ServiceDetails;
use Gls\GlsPoland\Entity\CourierCarrier;
use Gls\GlsPoland\Entity\ShopDeliveryCarrier;
use Gls\GlsPoland\PrestaShop\Helper\CarrierFinder;
use Gls\GlsPoland\PrestaShop\Order\Exception\MissingOrderParcelShopException;
use Gls\GlsPoland\Repository\CheckoutSessionRepository;
use Gls\GlsPoland\Repository\OrderParcelShopRepository;

final class ServiceDetailsFactory
{
    private $carrierFinder;
    private $checkoutSessionRepository;
    private $orderParcelShopRepository;

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

    public function create(\Order $order): ServiceDetails
    {
        if (null === $carrier = $this->carrierFinder->findOneByCarrierId((int) $order->id_carrier)) {
            return new ServiceDetails();
        }

        return $carrier instanceof ShopDeliveryCarrier
            ? $this->getShopDeliveryServiceDetails($carrier, $order)
            : $this->getServiceDetails($carrier, $order);
    }

    private function getShopDeliveryServiceDetails(ShopDeliveryCarrier $carrier, \Order $order): ServiceDetails
    {
        $storedParcelShop = $this->orderParcelShopRepository->find((int) $order->id);
        if (null !== $storedParcelShop) {
            return (new ServiceDetails())->setParcelShopId($storedParcelShop->getParcelShopId());
        }

        $checkoutSession = $this->checkoutSessionRepository->find((int) $order->id_cart);
        $parcelShopId = $checkoutSession
            ? $checkoutSession->getParcelShopId($carrier->getId()->getValue())
            : null;
        if (null === $parcelShopId && $checkoutSession) {
            $parcelShopId = $checkoutSession->getParcelShopId((int) $order->id_carrier);
        }

        if (null === $parcelShopId || '' === trim((string) $parcelShopId)) {
            throw MissingOrderParcelShopException::create((int) $order->id);
        }

        return (new ServiceDetails())->setParcelShopId((string) $parcelShopId);
    }

    private function getServiceDetails(CourierCarrier $carrier, \Order $order): ServiceDetails
    {
        $codAmount = $carrier->isCashOnDelivery()
            ? (float) $order->total_paid_tax_incl
            : null;

        return (new ServiceDetails())
            ->setCashOnDeliveryAmount($codAmount)
            ->setDocumentReturn($carrier->isDocumentReturn())
            ->setSaturdayDelivery($carrier->isSaturdayDelivery())
            ->setTimeDefiniteService($carrier->getTimeDefiniteService());
    }
}
