<?php

declare(strict_types=1);

namespace App\State\Provider\Utils;

use ApiPlatform\Api\CompositeIdentifierParser;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResources\Utils\GpsCoordinate;
use App\Service\Utils\GpsCoordinateUtils;
use Exception;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;

/**
 * Class GpsCoordinateSearchingProvider : custom provider pour assurer l'alimentation de la ressource GpsCoordinate
 * @package App\DataProvider\Utils
 */
final class GpsCoordinateSearchingProvider implements ProviderInterface
{
    public function __construct(
        private GpsCoordinateUtils $gpsCoordinateUtils,
        private RequestStack $requestStack
    )
    { }

    /**
     * @param Operation $operation
     * @param mixed[] $uriVariables
     * @param mixed[] $context
     * @return GpsCoordinate[]|GpsCoordinate
     * @throws ClientExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     */
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): array | GpsCoordinate
    {
        if($operation instanceof GetCollection) {
            return $this->getCollection();
        }
        return $this->getItem($uriVariables['id']);
    }

    /**
     * @return GpsCoordinate[]
     * @throws ClientExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     */
    public function getCollection(): array
    {
        $request = $this->requestStack->getCurrentRequest();
        $responses = [];
        try{
            if($request){
                $addresses = $this->gpsCoordinateUtils->searchGpsCoordinates(
                    $request->get('street'),
                    $request->get('cp'),
                    $request->get('city')
                );
                foreach ($addresses as $address){
                    $responses[] = $this->gpsCoordinateUtils->createGpsCoordinate($address);
                }
            }
        }catch (Exception){
            $responses[] = new GpsCoordinate();
        }
        return $responses;
    }

    /**
     * @param string $id
     * @return GpsCoordinate
     * @throws ClientExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     */
    public function getItem(string $id): GpsCoordinate
    {
        $ids = CompositeIdentifierParser::parse($id);
        try{
            $address = $this->gpsCoordinateUtils->reverseGpsCoordinates((float) $ids['latitude'], (float) $ids['longitude']);
            $gpsCoordinateResponse = $this->gpsCoordinateUtils->createGpsCoordinate($address);
        }catch (Exception){
            $gpsCoordinateResponse = new GpsCoordinate();
        }
        return $gpsCoordinateResponse;
    }
}