<?php

use Mockery as m;

use EasyRdf\Http;

class BnfResolverTest extends TestCase
{
    const BNF_EMPTY_RDF_RESP = <<<EOT
{
  "head" : {
    "vars" : [
      "s",
      "o"
    ]
  },
  "results" : {
    "bindings" : [ ]
  }
}
EOT;
    const BNF_RDF_RESP = <<<EOT
{
  "head":{
    "link":[

    ],
    "vars":[
      "s",
      "o"
    ]
  },
  "results":{
    "distinct":false,
    "ordered":true,
    "bindings":[
      {
        "s":{
          "type":"uri",
          "value":"http://data.bnf.fr/ark:/12148/cb11946662b"
        },
        "o":{
          "type":"literal",
          "xml:lang":"fr",
          "value":"Parents et enfants"
        }
      }
    ]
  }
}
EOT;

    const BNF_2_ID_RDF_RESP = <<<EOT
{
  "head":{
    "link":[

    ],
    "vars":[
      "s",
      "o"
    ]
  },
  "results":{
    "distinct":false,
    "ordered":true,
    "bindings":[
      {
        "s":{
          "type":"uri",
          "value":"http://data.bnf.fr/ark:/12148/cb11946662b"
        },
        "o":{
          "type":"literal",
          "xml:lang":"fr",
          "value":"Parents et enfants"
        }
      },
      {
        "s":{
          "type":"uri",
          "value":"http://data.bnf.fr/ark:/12148/cb11965628b"
        },
        "o":{
          "type":"literal",
          "xml:lang":"fr",
          "value":"Frères et soeurs"
        }
      }
    ]
  }
}
EOT;


    private function setUpSparqlClient($queryResult) {
        $response = m::mock('EasyRdf\Http\Response')
            ->shouldReceive('isSuccessful')->andReturn(true)
            ->shouldReceive('getBody')->andReturn($queryResult)
            ->shouldReceive('getStatus')->andReturn(200)
            ->shouldReceive('getHeader')->andReturn('application/sparql-results+json;charset=UTF-8')
            ->mock();
        $this->httpClient = m::mock('EasyRdf\Http\Client')
            ->shouldReceive('setConfig')
            ->shouldReceive('resetParameters')
            ->shouldReceive('setHeaders')//->with(m::on(function($headers) { print("HEADER => $headers\n"); return true;}),m::on(function($value) { print("VALUE => $value\n"); return true;}))
            ->shouldReceive('setMethod')
            ->shouldReceive('setUri')//->with(m::on(function($uri) { print($uri."\n"); return true;}))
            ->shouldReceive('request')->andReturn($response)
            ->mock();
        Http::setDefaultHttpClient($this->httpClient);
        $this->bnfResolver = $this->app->make('CorpusParole\Services\BnfResolverInterface');
    }

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

    public function tearDown() {
        parent::tearDown();
        m::close();
    }

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

    /**
     * resolve parents et enfants
     * @return void
     */
    public function testResolveSingleId() {

        $this->setUpSparqlClient(self::BNF_RDF_RESP);

        $reslabel = $this->bnfResolver->getLabel("http://data.bnf.fr/ark:/12148/cb11946662b");

        $this->assertEquals('parents et enfants', $reslabel, "Result must be parents et enfants");
    }

    /**
     * resolve parents et enfants ark url
     * @return void
     */
    public function testResolveSingleIdArkUrl() {

        $this->setUpSparqlClient(self::BNF_RDF_RESP);

        $reslabel = $this->bnfResolver->getLabel("http://ark.bnf.fr/ark:/12148/cb11946662b");

        $this->assertEquals('parents et enfants', $reslabel, "Result must be parents et enfants");
    }

    /**
     * resolve parents et enfants, ark id
     * @return void
     */
    public function testResolveSingleIdArk() {

        $this->setUpSparqlClient(self::BNF_RDF_RESP);

        $reslabel = $this->bnfResolver->getLabel("ark:/12148/cb11946662b");

        $this->assertEquals('parents et enfants', $reslabel, "Result must be parents et enfants");
    }


    /**
     * resolve foo
     * @return void
     */
    public function testResolveBadId() {

        $this->setUpSparqlClient(self::BNF_EMPTY_RDF_RESP);

        $reslabel = $this->bnfResolver->getLabel('ark:/12148/cb12345678b');

        $this->assertNull($reslabel, "Result must be null");
    }

    /**
     * resolve foo
     * @return void
     * @expectedException        CorpusParole\Services\BnfResolverException
     * @expectedExceptionMessage the provided id "21dsasd;;" is not a BNF id
     * @expectedExceptionCode 0
     */
    public function testResolveBadFormat() {

        $this->setUpSparqlClient(self::BNF_EMPTY_RDF_RESP);

        $reslabel = $this->bnfResolver->getLabel('21dsasd;;');
    }

    /**
     * resolve foo
     * @return void
     * @expectedException        CorpusParole\Services\BnfResolverException
     * @expectedExceptionMessage the provided id "http://sdsasd.org/foo" is not a BNF id
     * @expectedExceptionCode 0
     */
    public function testResolveBadFormatFullId() {

        $this->setUpSparqlClient(self::BNF_EMPTY_RDF_RESP);

        $reslabel = $this->bnfResolver->getLabel('http://sdsasd.org/foo');
    }


    /**
     * resolve parents et enfants and frères et soeurs
     * @return void
     */
    public function testResolveMultipleId() {

        $this->setUpSparqlClient(self::BNF_2_ID_RDF_RESP);

        $reslabels = $this->bnfResolver->getLabels(['ark:/12148/cb11965628b','ark:/12148/cb11946662b']);

        $this->assertCount(2, $reslabels, "Must have 2 results");
        $this->assertArrayHasKey('ark:/12148/cb11946662b', $reslabels);
        $this->assertArrayHasKey('ark:/12148/cb11965628b', $reslabels);

        $this->assertEquals('parents et enfants', $reslabels['ark:/12148/cb11946662b'], "Result for ark:/12148/cb11965628b must be parents et enfants");
        $this->assertEquals('frères et soeurs', $reslabels['ark:/12148/cb11965628b'], "Result for ark:/12148/cb11946662b must be frères et soeurs");
    }

    /**
     * resolve parents et enfants and frères et soeurs
     * @return void
     */
    public function testResolveMultipleFullIdArkUrl() {

        $this->setUpSparqlClient(self::BNF_2_ID_RDF_RESP);

        $reslabels = $this->bnfResolver->getLabels(['http://ark.bnf.fr/ark:/12148/cb11946662b','http://ark.bnf.fr/ark:/12148/cb11965628b']);

        $this->assertCount(2, $reslabels, "Must have 2 results");
        $this->assertArrayHasKey('http://ark.bnf.fr/ark:/12148/cb11946662b', $reslabels);
        $this->assertArrayHasKey('http://ark.bnf.fr/ark:/12148/cb11965628b', $reslabels);

        $this->assertEquals('parents et enfants', $reslabels['http://ark.bnf.fr/ark:/12148/cb11946662b'], "Result for http://ark.bnf.fr/ark:/12148/cb11946662b must be parents et enfants");
        $this->assertEquals('frères et soeurs', $reslabels['http://ark.bnf.fr/ark:/12148/cb11965628b'], "Result for http://ark.bnf.fr/ark:/12148/cb11965628b must be frères et soeurs");
    }

    /**
     * resolve parents et enfants and frères et soeurs
     * @return void
     */
    public function testResolveMultipleFullIdDataUrl() {

        $this->setUpSparqlClient(self::BNF_2_ID_RDF_RESP);

        $reslabels = $this->bnfResolver->getLabels(['http://data.bnf.fr/ark:/12148/cb11946662b','http://data.bnf.fr/ark:/12148/cb11965628b']);

        $this->assertCount(2, $reslabels, "Must have 2 results");
        $this->assertArrayHasKey('http://data.bnf.fr/ark:/12148/cb11946662b', $reslabels);
        $this->assertArrayHasKey('http://data.bnf.fr/ark:/12148/cb11965628b', $reslabels);

        $this->assertEquals('parents et enfants', $reslabels['http://data.bnf.fr/ark:/12148/cb11946662b'], "Result for http://data.bnf.fr/ark:/12148/cb11946662b must be parents et enfants");
        $this->assertEquals('frères et soeurs', $reslabels['http://data.bnf.fr/ark:/12148/cb11965628b'], "Result for http://data.bnf.fr/ark:/12148/cb11965628b must be frères et soeurs");
    }

    /**
     * check query
     * @return void
     */
    public function testQuery() {

        $expectedUri = config('corpusparole.bnf_query_url')."?query=SELECT+%3Fs+%3Fo+WHERE+%7B%7B+%3Chttp%3A%2F%2Fdata.bnf.fr%2Fark%3A%2F12148%2Fcb11946662b%3E+%3Chttp%3A%2F%2Fwww.w3.org%2F2004%2F02%2Fskos%2Fcore%23prefLabel%3E+%3Fo.+%3Fs+%3Chttp%3A%2F%2Fwww.w3.org%2F2004%2F02%2Fskos%2Fcore%23prefLabel%3E+%3Fo.+FILTER%28%3Fs+%3D+%3Chttp%3A%2F%2Fdata.bnf.fr%2Fark%3A%2F12148%2Fcb11946662b%3E+%26%26+lang%28%3Fo%29+%3D+%22fr%22%29%7D+UNION+%7B+%3Chttp%3A%2F%2Fdata.bnf.fr%2Fark%3A%2F12148%2Fcb11965628b%3E+%3Chttp%3A%2F%2Fwww.w3.org%2F2004%2F02%2Fskos%2Fcore%23prefLabel%3E+%3Fo.+%3Fs+%3Chttp%3A%2F%2Fwww.w3.org%2F2004%2F02%2Fskos%2Fcore%23prefLabel%3E+%3Fo.+FILTER%28%3Fs+%3D+%3Chttp%3A%2F%2Fdata.bnf.fr%2Fark%3A%2F12148%2Fcb11965628b%3E+%26%26+lang%28%3Fo%29+%3D+%22fr%22%29%7D%7D";
        $response = m::mock('EasyRdf\Http\Response')
            ->shouldReceive('isSuccessful')->andReturn(true)
            ->shouldReceive('getBody')->andReturn(self::BNF_EMPTY_RDF_RESP) //result not important
            ->shouldReceive('getStatus')->andReturn(200)
            ->shouldReceive('getHeader')->andReturn('application/sparql-results+json;charset=UTF-8')
            ->mock();
        $this->httpClient = m::mock('EasyRdf\Http\Client')
            ->shouldReceive('setConfig')
            ->shouldReceive('resetParameters')
            ->shouldReceive('setHeaders')//->with(m::on(function($headers) { print("HEADER => $headers\n"); return true;}),m::on(function($value) { print("VALUE => $value\n"); return true;}))
            ->shouldReceive('setMethod')
            ->shouldReceive('setUri')
            ->with($expectedUri)
            //->with(m::on(function($uri) { print($uri."\n"); return true;}))
            ->shouldReceive('request')->andReturn($response)
            ->mock();
        Http::setDefaultHttpClient($this->httpClient);
        $this->bnfResolver = $this->app->make('CorpusParole\Services\BnfResolverInterface');

        $reslabels = $this->bnfResolver->getLabels(['ark:/12148/cb11946662b','ark:/12148/cb11965628b']);

    }

}
