<?php
namespace App\Tests\Unit\Service\Utils;

use App\Service\Utils\GpsCoordinateUtils;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;

class GpsCoordinateUtilsTest extends TestCase
{
    private HttpClientInterface $client;

    public function setUp(): void
    {
        $this->client = $this->getMockBuilder(HttpClientInterface::class)->disableOriginalConstructor()->getMock();
    }

    /**
     * @see GpsCoordinateUtils::searchGpsCoordinates()
     */
    public function testSearchGpsCoordinates():void
    {
        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
            ->setConstructorArgs([$this->client])
            ->setMethodsExcept(['searchGpsCoordinates'])
            ->getMock();

        $response = $this->getMockBuilder(ResponseInterface::class)->getMock();
        $response->method('getContent')->willReturn('{"data":1}');  // dummy response data

        $this->client
            ->expects(self::once())
            ->method('request')
            ->with(
                'GET',
                'search?addressdetails=1&format=json&limit=10&street=11 chemin des rirtes&postalcode=74300&city=nancy-sur-cluses'
            )
            ->willReturn($response);

        $content = $gpsCoordinateUtils->searchGpsCoordinates('11 chemin des rirtes', '74300', 'nancy-sur-cluses');

        $this->assertEquals(['data' => 1], $content);
    }

    /**
     * @see GpsCoordinateUtils::searchGpsCoordinates()
     */
    public function testSearchGpsCoordinatesFailed():void
    {
        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
            ->setConstructorArgs([$this->client])
            ->setMethodsExcept(['searchGpsCoordinates'])
            ->getMock();

        $this->client
            ->expects(self::once())
            ->method('request')
            ->willThrowException(new \Exception());

        $this->expectException(NotFoundHttpException::class);
        $gpsCoordinateUtils->searchGpsCoordinates('...', '74300', '...');
    }

    /**
     * @see GpsCoordinateUtils::reverseGpsCoordinates()
     */
    public function testReverseGpsCoordinates():void
    {
        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
            ->setConstructorArgs([$this->client])
            ->setMethodsExcept(['reverseGpsCoordinates'])
            ->getMock();

        $response = $this->getMockBuilder(ResponseInterface::class)->getMock();
        $response->method('getContent')->willReturn('{"data":1}');  // dummy response data

        $this->client
            ->expects(self::once())
            ->method('request')
            ->with(
                'GET',
                'reverse?addressdetails=1&format=json&lat=46.040851602664&lon=6.58558355'
            )
            ->willReturn($response);

        $content = $gpsCoordinateUtils->reverseGpsCoordinates(46.04085160266434, 6.585583549999978);
        $this->assertEquals(['data' => 1], $content);
    }

    /**
     * @see GpsCoordinateUtils::reverseGpsCoordinates()
     */
    public function testReverseGpsCoordinatesFailed():void
    {
        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
            ->setConstructorArgs([$this->client])
            ->setMethodsExcept(['reverseGpsCoordinates'])
            ->getMock();

        $this->client
            ->expects(self::once())
            ->method('request')
            ->willThrowException(new \Exception());

        $this->expectException(NotFoundHttpException::class);
        $gpsCoordinateUtils->reverseGpsCoordinates(0000, 0000);
    }

    /**
     * @see GpsCoordinateUtils::createGpsCoordinate()
     */
    public function testCreateGpsCoordinate():void
    {
        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
            ->setConstructorArgs([$this->client])
            ->setMethodsExcept(['createGpsCoordinate'])
            ->getMock();

        $gpsApiResponse = [
            'address' => ['foo'],
            'lat' => 123.4,
            'lon' => 456.7,
        ];

        $gpsCoordinateUtils
            ->expects(self::once())
            ->method('transformAddress')
            ->with(['foo'])
            ->willReturn(
                [
                    'city' => 'bar',
                    'cp' => '12345',
                    'streetAddress' => '1 rue lambda',
                    'streetAddressSecond' => 'cedex 1'
                ]
            );

        $gpsCoordinate = $gpsCoordinateUtils->createGpsCoordinate($gpsApiResponse);

        $this->assertEquals(123.4, $gpsCoordinate->getLatitude());
        $this->assertEquals(456.7, $gpsCoordinate->getLongitude());
        $this->assertEquals('bar', $gpsCoordinate->getCity());
        $this->assertEquals('1 rue lambda', $gpsCoordinate->getStreetAddress());
        $this->assertEquals('cedex 1', $gpsCoordinate->getStreetAddressSecond());
    }

    /**
     * @see GpsCoordinateUtils::transformAddress()
     */
    public function testTransformAddress():void
    {
        $gpsCoordinateUtils = $this->getMockBuilder(GpsCoordinateUtils::class)
            ->setConstructorArgs([$this->client])
            ->setMethodsExcept(['transformAddress'])
            ->getMock();

        $arrayAddress = [
            'road' => 'foo',
            'hamlet' => 'bar',
            'town' => 'alpha',
            'postcode' => '12345'
        ];

        $addressTransformed = $gpsCoordinateUtils->transformAddress($arrayAddress);

        $this->assertEquals([
              "streetAddress" => "foo",
              "streetAddressSecond" => "bar",
              "city" => "alpha",
              "cp" => "12345"
            ], $addressTransformed);
    }
}
