<?php
namespace boru\ai\Tests\Provider\Gemini;

use boru\ai\Provider\Gemini\GeminiMapper;
use boru\ai\Provider\Gemini\GeminiStreamParser;
use boru\ai\Provider\ProviderSignal;
use PHPUnit\Framework\TestCase;

class GeminiStreamParserTest extends TestCase
{
    public function testParsesTextDeltasAndBuildsFinalResponse()
    {
        $parser = new GeminiStreamParser(new GeminiMapper());
        $signals = array();

        $parser->push("data: {\"candidates\":[{\"content\":{\"parts\":[{\"text\":\"Hello \"}]}}]}\n\n", function ($signal) use (&$signals) {
            $signals[] = $signal;
        });
        $parser->push("data: {\"candidates\":[{\"content\":{\"parts\":[{\"text\":\"world\"}]},\"finishReason\":\"STOP\"}],\"modelVersion\":\"gemini-2.5-pro\",\"responseId\":\"resp_1\"}\n\n", function ($signal) use (&$signals) {
            $signals[] = $signal;
        });

        $final = $parser->finalResponse();

        $this->assertNotNull($final);
        $this->assertSame('Hello world', $final->text());
        $this->assertCount(4, $signals);
        $this->assertSame(ProviderSignal::TEXT_DELTA, $signals[0]->type());
        $this->assertSame('Hello ', $signals[0]->data('delta'));
        $this->assertSame(ProviderSignal::TEXT_DELTA, $signals[1]->type());
        $this->assertSame('world', $signals[1]->data('delta'));
        $this->assertSame(ProviderSignal::RESPONSE_COMPLETED, $signals[2]->type());
        $this->assertSame(ProviderSignal::TEXT_COMPLETED, $signals[3]->type());
    }

    public function testEmitsToolCallSignalsWhenGeminiStreamsFunctionCallPart()
    {
        $parser = new GeminiStreamParser(new GeminiMapper());
        $signals = array();

        $parser->push("data: {\"candidates\":[{\"content\":{\"parts\":[{\"functionCall\":{\"name\":\"get_current_temperature\",\"args\":{\"location\":\"Atlanta, GA\",\"unit\":\"Fahrenheit\"}}}],\"role\":\"model\"},\"finishReason\":\"STOP\",\"finishMessage\":\"Model generated function call(s).\"}],\"modelVersion\":\"gemini-2.5-pro\",\"responseId\":\"resp_tool_1\"}\n\n", function ($signal) use (&$signals) {
            $signals[] = $signal;
        });

        $this->assertCount(4, $signals);
        $this->assertSame(ProviderSignal::TOOL_CALL_STARTED, $signals[0]->type());
        $this->assertSame('get_current_temperature', $signals[0]->data('tool_name'));
        $this->assertSame('Atlanta, GA', $signals[0]->data('arguments')['location']);
        $this->assertSame(ProviderSignal::TOOL_CALL_ARGUMENTS_DELTA, $signals[1]->type());
        $this->assertSame(ProviderSignal::TOOL_CALL_COMPLETED, $signals[2]->type());
        $this->assertSame('Model generated function call(s).', $signals[2]->data('finish_message'));
        $this->assertSame(ProviderSignal::RESPONSE_COMPLETED, $signals[3]->type());
    }
}
