<?php

declare(strict_types=1);

namespace Gls\GlsPoland\PrestaShop\EventListener;

use Gls\GlsPoland\Configuration\Orders;
use Gls\GlsPoland\Entity\Consignment;
use Gls\GlsPoland\MessageHandler\Consignment\ConsignmentEvent;
use Gls\GlsPoland\MessageHandler\Labels\LabelsEvent;
use Gls\GlsPoland\PrestaShop\ObjectModel\Repository\OrderRepository;
use Gls\GlsPoland\PrestaShop\ObjectModel\Repository\OrderStateRepository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

final class UpdateOrderStatusListener implements EventSubscriberInterface
{
    private $configuration;
    private $orderRepository;
    private $orderStatusRepository;

    private $hadTrackingNumbers;

    public function __construct(Orders\ConfigurationInterface $configuration, OrderRepository $orderRepository, OrderStateRepository $orderStatusRepository)
    {
        $this->configuration = $configuration;
        $this->orderRepository = $orderRepository;
        $this->orderStatusRepository = $orderStatusRepository;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            LabelsEvent::PRINT_BEFORE => 'onLabelPrintBefore',
            LabelsEvent::PRINTED => 'onLabelPrinted',
            ConsignmentEvent::DELETED => 'onConsignmentDeleted',
        ];
    }

    public function onLabelPrintBefore(LabelsEvent $event): void
    {
        $this->hadTrackingNumbers = $event->getConsignment()->hasParcelNumbers();
    }

    public function onLabelPrinted(LabelsEvent $event): void
    {
        $hadTrackingNumbers = $this->hadTrackingNumbers;
        $this->hadTrackingNumbers = null;

        if ($hadTrackingNumbers) {
            return;
        }

        $this->setOrderStatus(
            $event->getConsignment(),
            $this->configuration->getLabelPrintedOrderStatusId()
        );
    }

    public function onConsignmentDeleted(ConsignmentEvent $event): void
    {
        $this->setOrderStatus(
            $event->getConsignment(),
            $this->configuration->getConsignmentDeletedOrderStatusId()
        );
    }

    private function setOrderStatus(Consignment $consignment, ?int $statusId): void
    {
        if (null === $statusId || null === $this->orderStatusRepository->find($statusId)) {
            return;
        }

        $order = $this->orderRepository->find($consignment->getOrderId());
        if (null === $order || $statusId === (int) $order->getCurrentState()) {
            return;
        }

        $order->setCurrentState($statusId);
    }
}
