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

use boru\ai\AI;
use boru\ai\Runtime\AbstractTool;
use boru\ai\Runtime\ToolDefinition;
use boru\ai\Runtime\ToolRegistry;
use PHPUnit\Framework\TestCase;

class ToolRegistryTest extends TestCase
{
    protected function setUp(): void
    {
        AI::toolRegistry(new ToolRegistry());
    }

    public function testRegistersAndRetrievesToolDefinition()
    {
        $registry = new ToolRegistry();
        $definition = new ToolDefinition();
        $definition->name('weather_lookup')
            ->description('Look up weather')
            ->schema(array(
                'type' => 'object',
                'properties' => array(
                    'location' => array('type' => 'string'),
                ),
            ))
            ->callback(function () {
                return 'ok';
            });

        $registry->register($definition);

        $this->assertTrue($registry->has('weather_lookup'));
        $this->assertSame($definition, $registry->get('weather_lookup'));
    }

    public function testExportsSchemasWithoutCallbacks()
    {
        $registry = new ToolRegistry();
        $registry->define(
            'get_current_temperature',
            'Get the current temperature',
            array(
                'type' => 'object',
                'properties' => array(
                    'location' => array('type' => 'string'),
                ),
            ),
            function () {
                return '69';
            }
        );

        $schemas = $registry->exportSchemas();

        $this->assertCount(1, $schemas);
        $this->assertSame('get_current_temperature', $schemas[0]['name']);
        $this->assertArrayHasKey('schema', $schemas[0]);
        $this->assertArrayNotHasKey('callback', $schemas[0]);
    }

    public function testRegistersClassBasedTool()
    {
        $registry = new ToolRegistry();
        $tool = new ClassBasedWeatherTool();

        $registry->register($tool);
        $definition = $registry->get('get_current_temperature');

        $this->assertInstanceOf(ToolDefinition::class, $definition);
        $this->assertSame('get_current_temperature', $definition->name());
        $this->assertSame('Get the current temperature for a location', $definition->description());
        $this->assertSame('Atlanta, GA', $definition->invoke(array('location' => 'Atlanta, GA'), null));
    }

    public function testAIAddToolAcceptsClassBasedTool()
    {
        $ai = AI::provider('openai');
        $tool = new ClassBasedWeatherTool();

        $ai->addTool($tool);

        $request = $ai->request();
        $tools = $request->tools();

        $this->assertCount(1, $tools);
        $this->assertSame('get_current_temperature', $tools[0]['name']);
        $this->assertSame('Get the current temperature for a location', $tools[0]['description']);
        $this->assertTrue(AI::toolRegistry()->has('get_current_temperature'));
    }
}

class ClassBasedWeatherTool extends AbstractTool
{
    public function name()
    {
        return 'get_current_temperature';
    }

    public function description()
    {
        return 'Get the current temperature for a location';
    }

    public function schema()
    {
        return array(
            'type' => 'object',
            'properties' => array(
                'location' => array('type' => 'string'),
            ),
            'required' => array('location'),
        );
    }

    public function handle(array $arguments, \boru\ai\Runtime\ToolExecutionContext $context = null)
    {
        return isset($arguments['location']) ? $arguments['location'] : 'unknown';
    }
}
