<?php

declare(strict_types=1);

namespace ContextPaging\Tests;

use ContextPaging\OpenAICompatibleClient;
use ContextPaging\ToolCallMode;
use ContextPaging\ToolFormatter;
use ContextPaging\ToolCallParser;
use PHPUnit\Framework\TestCase;

/**
 * Tests for OpenAICompatibleClient using a real SmolLM3 endpoint.
 */
class OpenAICompatibleClientTest extends TestCase
{
    private OpenAICompatibleClient $client;
    private string $model = 'HuggingFaceTB/SmolLM3-3B';

    protected function setUp(): void
    {
        $this->client = new OpenAICompatibleClient(
            baseUrl: 'http://95.179.247.150/v1',
            apiKey: null,
            timeout: 120,
            verifySsl: false
        );
    }

    public function testBasicChatCompletion(): void
    {
        $messages = [
            ['role' => 'user', 'content' => 'Say "test successful" exactly.'],
        ];

        $response = $this->client->chat($messages, ['model' => $this->model, 'max_tokens' => 20]);

        $this->assertEquals(200, $response->getStatusCode());

        $body = json_decode($response->getBody()->getContents(), true);

        $this->assertArrayHasKey('choices', $body);
        $this->assertCount(1, $body['choices']);
        $this->assertArrayHasKey('message', $body['choices'][0]);
        $this->assertEquals('assistant', $body['choices'][0]['message']['role']);
        $this->assertNotEmpty($body['choices'][0]['message']['content']);
    }

    public function testUsageStatsReturned(): void
    {
        $messages = [
            ['role' => 'user', 'content' => 'Hello'],
        ];

        $response = $this->client->chat($messages, ['model' => $this->model, 'max_tokens' => 20]);
        $body = json_decode($response->getBody()->getContents(), true);

        $this->assertArrayHasKey('usage', $body);
        $this->assertArrayHasKey('prompt_tokens', $body['usage']);
        $this->assertArrayHasKey('completion_tokens', $body['usage']);
        $this->assertArrayHasKey('total_tokens', $body['usage']);

        $this->assertGreaterThan(0, $body['usage']['prompt_tokens']);
        $this->assertGreaterThan(0, $body['usage']['completion_tokens']);
    }

    public function testMultiTurnConversation(): void
    {
        $messages = [
            ['role' => 'user', 'content' => 'My name is TestBot.'],
            ['role' => 'assistant', 'content' => 'Nice to meet you, TestBot!'],
            ['role' => 'user', 'content' => 'What is my name?'],
        ];

        $response = $this->client->chat($messages, ['model' => $this->model, 'max_tokens' => 50]);
        $body = json_decode($response->getBody()->getContents(), true);

        $this->assertEquals(200, $response->getStatusCode());
        $content = strtolower($body['choices'][0]['message']['content']);
        $this->assertStringContainsString('testbot', $content);
    }

    public function testListModels(): void
    {
        $response = $this->client->listModels();
        $this->assertEquals(200, $response->getStatusCode());
        $body = json_decode($response->getBody()->getContents(), true);
        $this->assertArrayHasKey('data', $body);
        $this->assertIsArray($body['data']);
    }

    public function testRawToolFormatting(): void
    {
        $formatter = new ToolFormatter(ToolCallMode::RAW);

        $messages = [
            ['role' => 'system', 'content' => 'You are a helpful assistant.'],
            ['role' => 'user', 'content' => 'Test'],
        ];

        $tools = [ToolFormatter::FETCH_MESSAGE_TOOL];

        $payload = $formatter->buildPayload($messages, ['model' => $this->model], $tools, ToolCallMode::RAW);

        $this->assertArrayNotHasKey('tools', $payload);

        $this->assertEquals('system', $payload['messages'][0]['role']);
        $systemContent = $payload['messages'][0]['content'];
        
        $this->assertStringContainsString('<tools>', $systemContent);
        $this->assertStringContainsString('fetch_message', $systemContent);
    }

    public function testToolCallParserDetectsRawMode(): void
    {
        $parser = new ToolCallParser(ToolCallMode::AUTO);

        $response = [
            'choices' => [
                [
                    'message' => [
                        'role' => 'assistant',
                        'content' => '<tool_call>{"name": "fetch_message", "arguments": {"md5": "abc123"}}</tool_call>',
                    ],
                ],
            ],
        ];

        $detected = $parser->detectMode($response);
        $this->assertEquals(ToolCallMode::RAW, $detected);
    }

    public function testToolCallParserExtractsRawToolCall(): void
    {
        $parser = new ToolCallParser(ToolCallMode::RAW);

        $response = [
            'choices' => [
                [
                    'message' => [
                        'role' => 'assistant',
                        'content' => '<tool_call>{"name": "fetch_message", "arguments": {"md5": "abc123def456"}}</tool_call>',
                    ],
                ],
            ],
        ];

        $toolCalls = $parser->extract($response);

        $this->assertNotNull($toolCalls);
        $this->assertCount(1, $toolCalls);
        $this->assertEquals('fetch_message', $toolCalls[0]['name']);
        $this->assertEquals('abc123def456', $toolCalls[0]['arguments']['md5']);
    }
}
