<?php
namespace boru\ai\Tests\Mcp;

use boru\ai\Http\HttpResponse;
use boru\ai\Mcp\HttpProxyMcpClient;
use boru\ai\Mcp\HttpProxyMcpClientFactory;
use boru\ai\Mcp\McpServerConfig;
use boru\ai\Tests\Fakes\FakeHttpClient;
use PHPUnit\Framework\TestCase;

class HttpProxyMcpClientTest extends TestCase
{
    public function testListToolsBuildsHttpProxyRequestWithDerivedAuthHeaders()
    {
        $httpClient = new FakeHttpClient();
        $response = new HttpResponse();
        $response->statusCode(200)->body('{"tools":[{"name":"read_file"}]}');
        $httpClient->queueResponse($response);

        $client = new HttpProxyMcpClient($httpClient, array('timeout' => 7));
        $client->initialize(new McpServerConfig(array(
            'name' => 'filesystem',
            'transport' => 'http',
            'url' => 'https://proxy.example.com/mcp',
            'headers' => array(
                'internal-port' => '9000',
            ),
            'auth' => array(
                'type' => 'bearer',
                'token' => 'secret-token',
            ),
        )));

        $tools = $client->listTools();

        $this->assertCount(1, $tools);
        $this->assertSame('read_file', $tools[0]['name']);
        $this->assertCount(1, $httpClient->requests);
        $request = $httpClient->requests[0];
        $this->assertSame('POST', $request->method());
        $this->assertSame('https://proxy.example.com/mcp/tools/list', $request->url());
        $this->assertSame('9000', $request->header('internal-port'));
        $this->assertSame('Bearer secret-token', $request->header('Authorization'));
        $this->assertSame('application/json', $request->header('Accept'));
        $this->assertSame(7, $request->option('timeout'));
        $this->assertNull($request->json());
    }

    public function testCallToolBuildsJsonRequestAndReturnsDecodedPayload()
    {
        $httpClient = new FakeHttpClient();
        $response = new HttpResponse();
        $response->statusCode(200)->body('{"content":[{"type":"text","text":"ok"}],"structuredContent":{"status":"ok"}}');
        $httpClient->queueResponse($response);

        $client = new HttpProxyMcpClient($httpClient);
        $client->initialize(new McpServerConfig(array(
            'name' => 'filesystem',
            'transport' => 'http',
            'url' => 'https://proxy.example.com/mcp',
        )));

        $result = $client->callTool('read_file', array('path' => '/tmp/example.txt'));

        $this->assertSame('ok', $result['content'][0]['text']);
        $request = $httpClient->requests[0];
        $this->assertSame('https://proxy.example.com/mcp/tools/call', $request->url());
        $this->assertSame('application/json', $request->header('Content-Type'));
        $this->assertSame('read_file', $request->json()['name']);
        $this->assertSame('/tmp/example.txt', $request->json()['arguments']['path']);
    }

    public function testListToolsThrowsOnErrorResponses()
    {
        $httpClient = new FakeHttpClient();
        $response = new HttpResponse();
        $response->statusCode(502)->body('{"message":"Upstream tools/list error"}');
        $httpClient->queueResponse($response);

        $client = new HttpProxyMcpClient($httpClient);
        $client->initialize(new McpServerConfig(array(
            'name' => 'filesystem',
            'transport' => 'http',
            'url' => 'https://proxy.example.com/mcp',
        )));

        $this->expectException(\RuntimeException::class);
        $this->expectExceptionMessage('Upstream tools/list error');

        $client->listTools();
    }

    public function testFactoryCreatesHttpProxyClientInstances()
    {
        $factory = new HttpProxyMcpClientFactory(new FakeHttpClient(), array('timeout' => 5));
        $client = $factory->makeClient(new McpServerConfig(array(
            'name' => 'filesystem',
            'transport' => 'http',
            'url' => 'https://proxy.example.com/mcp',
        )));

        $this->assertInstanceOf(HttpProxyMcpClient::class, $client);
    }
}
