<?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\Controller\Front\Checkout;

use InPost\International\Api\Exception\ApiClientExceptionInterface;
use InPost\International\Api\Point\Model\PointCapability;
use InPost\International\Checkout\Form\Model\Address as FormData;
use InPost\International\Checkout\Form\Type\AddressType;
use InPost\International\Checkout\View\Model\ClosestPointView;
use InPost\International\Delivery\Address;
use InPost\International\Delivery\Point\ClosestPointFinderInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;

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

final class FindClosestPointController
{
    /**
     * @var \Context
     */
    private $context;

    /**
     * @var FormFactoryInterface
     */
    private $formFactory;

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

    public function __construct(\Context $context, FormFactoryInterface $formFactory, ClosestPointFinderInterface $finder)
    {
        $this->context = $context;
        $this->formFactory = $formFactory;
        $this->finder = $finder;
    }

    public function __invoke(Request $request): Response
    {
        $form = $this->formFactory->create(AddressType::class);
        $form->handleRequest($request);

        if (!$form->isSubmitted()) {
            throw new BadRequestHttpException(sprintf('Malformed request: "%s" is missing.', $form->getName()));
        }

        if (!$form->isValid()) {
            throw new UnprocessableEntityHttpException('Address data is not valid.');
        }

        $address = $this->createAddress($form->getData());

        try {
            $point = $this->finder->findClosestPoint($address, PointCapability::ParcelCollect());
        } catch (ApiClientExceptionInterface $e) {
            throw new HttpException(Response::HTTP_BAD_GATEWAY, 'Could not fetch point data from the API.', $e);
        }

        return new JsonResponse([
            'point' => null === $point ? null : new ClosestPointView($point, $this->context->getCurrentLocale()),
        ]);
    }

    private function createAddress(FormData $data): Address
    {
        return new Address(
            $data->getAddress(),
            $data->getPostcode(),
            $data->getCity(),
            $data->getCountry()
        );
    }
}
