<?php

use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Middleware;
use GuzzleHttp\Exception\RequestException;


class GeonamesResolverTest extends TestCase
{

    const TEST_INPUT_DOCS = [
        '2968801' => __DIR__.'/files/GeonamesResolverTest/geonames_rdf_2968801.rdf',
        '2988507' => __DIR__.'/files/GeonamesResolverTest/geonames_rdf_2988507.rdf',
        '6255148' => __DIR__.'/files/GeonamesResolverTest/geonames_rdf_6255148.rdf',
    ];

    private $inputGraphes = [];

    private function getClient($keys, &$container) {
        $history = Middleware::history($container);
        $responses = [];
        foreach ($keys as $key) {
            if(array_key_exists($key, self::TEST_INPUT_DOCS)) {
                array_push($responses, new Response(200, [], file_get_contents(self::TEST_INPUT_DOCS[$key])));
            }
            else {
                array_push($responses, new Response(intval($key)));
            }

        }
        $mock = new MockHandler($responses);
        $handler = HandlerStack::create($mock);
        $handler->push($history);

        return new Client(['handler' => $handler]);
    }

    public function setUp() {
        parent::setup();

        foreach(self::TEST_INPUT_DOCS as $key => $inputDoc) {
            $this->inputGraphes[$key] =  new EasyRdf\Graph(config('corpusparole.geonames_base_url').$key."/", file_get_contents($inputDoc));
        }
    }

    /**
     * Just test the setup.
     *
     * @return void
     */
    public function testSetup()
    {
        $this->assertTrue(true);
    }

    /**
     * test getLabel
     */
    public function testGetLabel() {

        $container = [];
        $client = $this->getClient(['2968801'], $container);

        $resolver = new \CorpusParole\Services\GeonamesResolver($client);
        $label = $resolver->getLabel('2968801');

        $this->assertEquals('Villedieu-les-Poêles', $label, "Label is Villedieu-les-Poêles");

        $this->assertCount(1, $container);

        $this->assertEquals("http://sws.geonames.org/2968801/", (string)$container[0]['request']->getUri());

    }

    /**
     * test getLabel
     */
    public function testGetLabel2988507() {

        $container = [];
        $client = $this->getClient(['2988507'], $container);

        $resolver = new \CorpusParole\Services\GeonamesResolver($client);
        $label = $resolver->getLabel('2988507');

        $this->assertEquals('Paris', $label, "Label is Paris");

        $this->assertCount(1, $container);

        $this->assertEquals("http://sws.geonames.org/2988507/", (string)$container[0]['request']->getUri());

    }

    /**
     * test getLabel
     */
    public function testGetLabel6255148() {

        $container = [];
        $client = $this->getClient(['6255148'], $container);

        $resolver = new \CorpusParole\Services\GeonamesResolver($client);
        $label = $resolver->getLabel('6255148');

        $this->assertEquals('Europe', $label, "Label is Europe");

        $this->assertCount(1, $container);

        $this->assertEquals("http://sws.geonames.org/6255148/", (string)$container[0]['request']->getUri());

    }


    /**
     * test getLabel 404
     */
    public function testGetLabel404() {
        $container = [];
        $client = $this->getClient(['404'], $container);

        $resolver = new \CorpusParole\Services\GeonamesResolver($client);

        $name = $resolver->getLabel('12345');

        $this->assertNull($name);

        $this->assertCount(1, $container);
        $this->assertEquals("http://sws.geonames.org/12345/", (string)$container[0]['request']->getUri());

    }

    /**
     * test getLabel unknown
     */
    public function testGetLabelUnknown() {
        $container = [];
        $client = $this->getClient(['6255148'], $container);

        $resolver = new \CorpusParole\Services\GeonamesResolver($client);

        $name = $resolver->getLabel('12345');

        $this->assertNull($name);

        $this->assertCount(1, $container);
        $this->assertEquals("http://sws.geonames.org/12345/", (string)$container[0]['request']->getUri());

    }

    /**
     * test getLabels
     */
    public function testGetLabels() {

        $container = [];
        $client = $this->getClient(['2968801', '2988507', '6255148'], $container);

        $resolver = new \CorpusParole\Services\GeonamesResolver($client);
        $labels = $resolver->getLabels(['2968801', '2988507', '6255148']);

        $this->assertEquals(['2968801' => 'Villedieu-les-Poêles', '2988507' => 'Paris', '6255148' => 'Europe'] , $labels);

        $this->assertCount(3, $container);

        $this->assertEquals("http://sws.geonames.org/2968801/", (string)$container[0]['request']->getUri());
        $this->assertEquals("http://sws.geonames.org/2988507/", (string)$container[1]['request']->getUri());
        $this->assertEquals("http://sws.geonames.org/6255148/", (string)$container[2]['request']->getUri());

    }

    /**
     * Test exception 401
     * @expectedException        CorpusParole\Services\GeonamesResolverException
     * @expectedExceptionMessage Client error: `GET http://sws.geonames.org/12345/` resulted in a `401 Unauthorized` response:
     * @expectedExceptionCode 401
     */
    public function test401Error() {
        $container = [];
        $client = $this->getClient(['401'], $container);

        $resolver = new \CorpusParole\Services\GeonamesResolver($client);

        $name = $resolver->getLabel('12345');
    }


    /**
     * Test exception 500
     * @expectedException        CorpusParole\Services\GeonamesResolverException
     * @expectedExceptionMessage Server error: `GET http://sws.geonames.org/12345/` resulted in a `500 Internal Server Error` response:
     * @expectedExceptionCode 500
     */
    public function test500Error() {
        $container = [];
        $client = $this->getClient(['500'], $container);

        $resolver = new \CorpusParole\Services\GeonamesResolver($client);

        $name = $resolver->getLabel('12345');
    }

    /**
     * Test exception malformed
     * @expectedException        CorpusParole\Services\GeonamesResolverException
     * @expectedExceptionMessage GeonamesId not in correct format
     * @expectedExceptionCode 400
     */
    public function testMalformedError() {
        $container = [];
        $client = $this->getClient(['200'], $container);

        $resolver = new \CorpusParole\Services\GeonamesResolver($client);

        $name = $resolver->getLabel('abcd');
    }




}
