<?php

declare(strict_types=1);
namespace Tests\Adawolfa\Retrofit;
use Adawolfa\Retrofit\Executor;
use Adawolfa\Retrofit\Factory;
use Adawolfa\Retrofit\NoConverterException;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Utils;
use Http\Mock\Client;
use PHPUnit\Framework\TestCase as TC;
use Psr\Http\Message\ResponseInterface;

final class BareServiceTest extends TC
{

	private Service $service;
	private Client  $client;

	public function testRoot(): void
	{
		$this->client->addResponse(new Response(body: 'hello'));
		$this->assertSame('hello', $this->service->root());
		$this->assertSame('root', (string) $this->client->getLastRequest()->getUri());
	}

	public function testReturnsMixed(): void
	{
		$this->client->addResponse(new Response(body: 'hello'));
		$this->assertInstanceOf(ResponseInterface::class, $this->service->returnMixed());
	}

	public function testNoReturnType(): void
	{
		$this->client->addResponse(new Response);
		$this->assertInstanceOf(ResponseInterface::class, $this->service->returnNoReturn());
	}

	public function testReturnResponse(): void
	{
		$this->client->addResponse(new Response);
		$this->assertInstanceOf(ResponseInterface::class, $this->service->returnResponse());
	}

	public function testReturnStream(): void
	{
		$this->client->addResponse(new Response(body: 'hello'));
		$this->assertSame('hello', $this->service->returnStream()->getContents());
	}

	public function testNoIntConverter(): void
	{
		$this->client->addResponse(new Response);
		$this->expectException(NoConverterException::class);
		$this->expectExceptionMessage('Tests\Adawolfa\Retrofit\Service::returnInt() has no supported converter to int.');
		$this->service->returnInt();
	}

	public function testHeaders(): void
	{
		$this->client->addResponse(new Response);
		$this->service->headers();
		$request = $this->client->getLastRequest();
		$this->assertSame([
			'A' => ['1'],
			'B' => ['2'],
			'C' => ['3', '4'],
		], $request->getHeaders());
	}

	public function testHeaderArgument(): void
	{
		$this->client->addResponse(new Response);
		$this->service->header('a', 'b');
		$request = $this->client->getLastRequest();
		$this->assertSame([
			'A' => ['b'],
		], $request->getHeaders());
	}

	public function testQuery(): void
	{
		$this->client->addResponse(new Response);
		$this->service->query('b');
		$request = $this->client->getLastRequest();
		$this->assertSame('a=a&b=b&c=1&x=1', $request->getUri()->getQuery());
	}

	public function testBodyString(): void
	{
		$this->client->addResponse(new Response);
		$this->service->body('hello');
		$this->assertSame('hello', $this->client->getLastRequest()->getBody()->getContents());
	}

	public function testBodyStream(): void
	{
		$this->client->addResponse(new Response);
		$this->service->body(Utils::streamFor('hello'));
		$this->assertSame('hello', $this->client->getLastRequest()->getBody()->getContents());
	}

	public function testURLEncodedBody(): void
	{
		$this->client->addResponse(new Response);
		$this->service->urlEncodedBody('foo');
		$request = $this->client->getLastRequest();
		parse_str($request->getBody()->getContents(), $post);
		$this->assertSame(['a' => 'foo'], $post);
	}

	protected function setUp(): void
	{
		$this->service = (new Factory())
			->withExecutor(new Executor($this->client = new Client))
			->create(Service::class);
	}

}