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

use boru\ai\Conversation\ConversationReference;
use boru\ai\Http\HttpResponse;
use boru\ai\Provider\Gemini\GeminiClient;
use boru\ai\Provider\Gemini\GeminiMapper;
use boru\ai\Provider\Gemini\GeminiProvider;
use boru\ai\Provider\ProviderRegistry;
use boru\ai\Runtime\Runtime;
use boru\ai\Runtime\RuntimeContext;
use boru\ai\Runtime\ToolExecutor;
use boru\ai\Runtime\ToolRegistry;
use boru\ai\Schema\Request;
use boru\ai\Tests\Fakes\FakeHttpClient;
use boru\ai\Tests\Fakes\FakePersistenceProvider;
use PHPUnit\Framework\TestCase;

class GeminiStreamingFailureTest extends TestCase
{
    public function testGeminiStreamingProviderErrorCausesRuntimeFailure()
    {
        $httpClient = new FakeHttpClient();
        $httpResponse = new HttpResponse();
        $httpResponse->statusCode(503)->body('{"error":{"code":503,"message":"Model overloaded","status":"UNAVAILABLE"}}');
        $httpClient->queueStream(array(
            "data: {\"error\":{\"code\":503,\"message\":\"Model overloaded\",\"status\":\"UNAVAILABLE\"}}\n\n",
        ), $httpResponse);

        $client = new GeminiClient('test-key', array(), $httpClient);
        $provider = new GeminiProvider($client, new GeminiMapper());

        $providerRegistry = new ProviderRegistry();
        $providerRegistry->register($provider);
        $providerRegistry->mapModelPrefix('gemini-', 'gemini');

        $persistence = new FakePersistenceProvider();
        $context = new RuntimeContext(
            $providerRegistry,
            $persistence,
            null,
            new ToolExecutor(new ToolRegistry()),
            new ToolRegistry()
        );

        $runtime = new Runtime($context);
        $request = new Request();
        $request->provider('gemini')->model('gemini-2.5-pro')->addMessage('Hello with streaming')->option('stream', true);

        try {
            $runtime->execute($request, new ConversationReference());
            $this->fail('Expected runtime to throw for Gemini streaming provider error');
        } catch (\RuntimeException $e) {
            $this->assertSame('Model overloaded', $e->getMessage());
            $this->assertSame(503, $e->getCode());
        }

        $lastTurn = $persistence->savedTurns[count($persistence->savedTurns) - 1];
        $this->assertSame('failed', $lastTurn->status());
        $this->assertSame('Model overloaded', $lastTurn->metadata('exception_message'));
        $this->assertSame('RuntimeException', $lastTurn->metadata('exception_class'));
    }
}
