<?php

declare(strict_types=1);

namespace Gls\GlsPoland\PrestaShop\Helper;

use Gls\GlsPoland\Entity\Carrier;
use Gls\GlsPoland\PrestaShop\ObjectModel\Repository\CarrierRepository as ObjectModelRepository;
use Gls\GlsPoland\Repository\CarrierRepository;

final class CarrierFinder
{
    private $entityRepository;
    private $objectModelRepository;

    private $carriers = [];

    public function __construct(CarrierRepository $entityRepository, ObjectModelRepository $objectModelRepository)
    {
        $this->entityRepository = $entityRepository;
        $this->objectModelRepository = $objectModelRepository;
    }

    public function findOneByCarrierId(int $carrierId): ?Carrier
    {
        if (array_key_exists($carrierId, $this->carriers)) {
            return $this->carriers[$carrierId];
        }

        if (null === $carrier = $this->objectModelRepository->find($carrierId)) {
            return $this->carriers[$carrierId] = null;
        }

        return $this->carriers[$carrierId] = $this->entityRepository->find((int) $carrier->id_reference);
    }

    public function findOneByReferenceId(int $referenceId): ?Carrier
    {
        if (0 >= $referenceId) {
            return null;
        }

        return $this->entityRepository->find($referenceId);
    }

    /**
     * @return Carrier[]
     */
    public function findByCarrierIds(int ...$carrierIds): array
    {
        $result = [];

        foreach ($carrierIds as $key => $carrierId) {
            if (!array_key_exists($carrierId, $this->carriers)) {
                continue;
            }

            unset($carrierIds[$key]);

            if (null !== $this->carriers[$carrierId]) {
                $result[$carrierId] = $this->carriers[$carrierId];
            }
        }

        if (
            [] === $carrierIds
            || [] === $objectModels = $this->objectModelRepository->findBy(['id_carrier' => $carrierIds])
        ) {
            return $result;
        }

        $carrierIdsByReferenceId = [];
        foreach ($objectModels as $objectModel) {
            $carrierIdsByReferenceId[(int) $objectModel->id_reference] = (int) $objectModel->id;
        }

        $carriers = $this->entityRepository->findBy(['id' => array_keys($carrierIdsByReferenceId)]);

        foreach ($carriers as $carrier) {
            $carrierId = $carrierIdsByReferenceId[$carrier->getId()->getValue()];
            $result[$carrierId] = $this->carriers[$carrierId] = $carrier;
        }

        return $result;
    }
}
