<?php

declare(strict_types=1);

namespace Gls\GlsPoland\MessageHandler\Pickup;

use Doctrine\ORM\EntityManagerInterface;
use Gls\GlsPoland\AdePlus\Common\Id;
use Gls\GlsPoland\AdePlus\Pickup\ClientInterface;
use Gls\GlsPoland\Entity\Consignment;
use Gls\GlsPoland\EventDispatcher\EventDispatcherInterface;
use Gls\GlsPoland\Message\CreatePickupCommand;
use Gls\GlsPoland\Repository\ConsignmentRepository;

final class CreatePickupHandler implements CreatePickupHandlerInterface
{
    private $repository;
    private $client;
    private $entityManager;
    private $dispatcher;

    public function __construct(ConsignmentRepository $repository, ClientInterface $client, EntityManagerInterface $entityManager, EventDispatcherInterface $dispatcher)
    {
        $this->repository = $repository;
        $this->client = $client;
        $this->entityManager = $entityManager;
        $this->dispatcher = $dispatcher;
    }

    public function handle(CreatePickupCommand $command): void
    {
        $consignments = $this->repository->findWithoutPickups(...$command->getConsignmentIds());
        if ([] === $consignments) {
            return;
        }

        $consignmentIds = array_map(static function (Consignment $consignment): int {
            return $consignment->getPreparingBoxId();
        }, $consignments);

        $pickupId = $this->client->createPickup($command->getDescription(), ...$consignmentIds);
        $this->updateConsignmentIds($consignments, $pickupId);

        $this->dispatcher->dispatch(new PickupCreatedEvent($pickupId, ...$consignments));
    }

    /**
     * @param Consignment[] $consignments
     */
    private function updateConsignmentIds(array $consignments, Id $pickupId): void
    {
        $dict = [];
        foreach ($consignments as $consignment) {
            $dict[$consignment->getPreparingBoxId()] = $consignment;
        }

        $bindings = $this->client->getConsignmentIdsBindings($pickupId->getId());
        foreach ($bindings as $binding) {
            $dict[$binding->getPreparingBoxId()]->setPickupId($pickupId, $binding);
        }

        $this->entityManager->flush();
    }
}
