<?php

namespace NeuronAI\Tests;

use NeuronAI\Tools\PropertyType;
use NeuronAI\Tools\ToolProperty;
use NeuronAI\Tools\Tool;
use NeuronAI\Tools\ToolInterface;
use PHPUnit\Framework\TestCase;

class ToolTest extends TestCase
{
    public function test_tool_instance()
    {
        $tool = new Tool('example', 'example');
        $this->assertInstanceOf(ToolInterface::class, $tool);

        $tool->setInputs(null);
        $this->assertEquals([], $tool->getInputs());

        $tool->setCallId(null); // Tool call ID is not generated by all providers
        $this->assertEquals(null, $tool->getCallId());
        $tool->setCallId('test');
        $this->assertEquals('test', $tool->getCallId());
    }

    public function test_required_properties()
    {
        $tool = Tool::make('test', 'Test tool')
            ->addProperty(
                new ToolProperty('name', PropertyType::STRING, 'User name', true)
            )
            ->addProperty(
                new ToolProperty('surname', PropertyType::STRING, 'User surname', false)
            )
            ->addProperty(
                new ToolProperty('age', PropertyType::INTEGER, 'User age', true)
            )
            ->setCallable(function (): void {});

        $properties = $tool->getRequiredProperties();
        $this->assertEquals(['name', 'age'], $properties);
    }

    public function test_tool_return_value()
    {
        $tool = Tool::make('test', 'Test tool');

        $tool->setCallable(fn () => 'test')->execute();
        $this->assertEquals('test', $tool->getResult());

        $tool->setCallable(fn () => ['test'])->execute();
        $this->assertEquals('["test"]', $tool->getResult());

        $tool->setCallable(fn () => ['foo' => 'bar'])->execute();
        $this->assertEquals('{"foo":"bar"}', $tool->getResult());

        $tool->setCallable(fn () => new class () {
            public function __toString(): string
            {
                return 'test';
            }
        })->execute();
        $this->assertEquals('test', $tool->getResult());
    }

    public function test_invalid_return_type()
    {
        $tool = Tool::make('test', 'Test tool');

        $this->expectException(\TypeError::class);

        $tool->setCallable(fn () => new class () {})->execute();
    }
}
