<?php
/**
 * Copyright since 2025 InPost S.A.
 *
 * For the full license information, please view the LICENSE file bundled with the module.
 *
 * @author InPost S.A.
 * @copyright since 2025 InPost S.A.
 * @license MIT
 */

declare(strict_types=1);

namespace InPost\International\Checkout\View\Builder;

use InPost\International\Api\Point\Model\PointCapability;
use InPost\International\Checkout\View\Model\CheckoutView;
use InPost\International\Checkout\View\Model\ClosestPointView;
use InPost\International\Country;
use InPost\International\Delivery\Address;
use InPost\International\Delivery\Point\ClosestPointFinderInterface;
use InPost\International\PrestaShop\ObjectModel\Repository\ObjectRepositoryInterface;

if (!defined('_PS_VERSION_')) {
    exit;
}

final class ClosestPointViewBuilder implements CheckoutViewBuilderInterface
{
    /**
     * @var \Context
     */
    private $context;

    /**
     * @var ObjectRepositoryInterface<\Country>
     */
    private $countryRepository;

    /**
     * @var ClosestPointFinderInterface
     */
    private $pointFinder;

    /**
     * @param ObjectRepositoryInterface<\Country> $countryRepository
     */
    public function __construct(\Context $context, ObjectRepositoryInterface $countryRepository, ClosestPointFinderInterface $pointFinder)
    {
        $this->context = $context;
        $this->countryRepository = $countryRepository;
        $this->pointFinder = $pointFinder;
    }

    public function buildView(CheckoutView $view): void
    {
        if (null === $address = $this->getDeliveryAddress($view->getCart())) {
            return;
        }

        try {
            $point = $this->pointFinder->findClosestPoint($address, PointCapability::ParcelCollect());
        } catch (\Exception $e) {
            return;
        }

        if (null === $point) {
            return;
        }

        $pointView = new ClosestPointView($point, $this->context->getCurrentLocale());
        $view->setClosestPoint($pointView);
    }

    private function getDeliveryAddress(\Cart $cart): ?Address
    {
        if (0 >= $addressId = (int) $cart->id_address_delivery) {
            return null;
        }

        /** @var \Address[] $addresses */
        $addresses = $cart->getAddressCollection();

        if (null === $address = $addresses[$addressId] ?? null) {
            return null;
        }

        if ('' === $postcode = trim((string) $address->postcode)) {
            return null;
        }

        if (null === $country = $this->getCountry($address)) {
            return null;
        }

        return new Address(
            $this->formatAddress($address),
            $postcode,
            trim((string) $address->city),
            $country
        );
    }

    private function getCountry(\Address $address): ?Country
    {
        if (null === $country = $this->countryRepository->find((int) $address->id_country)) {
            return null;
        }

        return Country::tryFrom((string) $country->iso_code);
    }

    private function formatAddress(\Address $address): string
    {
        $address1 = trim((string) $address->address1);

        if ('' === $address2 = trim((string) $address->address2)) {
            return $address1;
        }

        return sprintf('%s %s', $address1, $address2);
    }
}
