<?php

namespace App\Agent;

use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Tools\Request;
use Laravel\Ai\Tools\ToolNameResolver;
use Stringable;

/**
 * Presents a tool to the model under a namespaced name.
 *
 * Two teams can both ship a "list" tool; the model sees `creative__list` and
 * `campaign__list` and can tell from the name alone which part of the product
 * it is reaching into. The wrapped tool is unchanged and knows nothing about
 * this, so a module's tools stay plain and testable on their own.
 *
 * The separator is a double underscore rather than a dot because OpenAI
 * rejects anything outside [a-zA-Z0-9_-] in a tool name, with a 400 at request
 * time rather than a clear error. Gemini accepts dots, so this only shows up
 * once you switch provider.
 *
 * laravel/ai resolves a name via ToolNameResolver, which prefers a name()
 * method when one exists. That is the hook this relies on.
 */
class NamespacedTool implements Tool
{
    public function __construct(
        private readonly string $namespace,
        private readonly Tool $tool,
    ) {}

    /** The separator every provider accepts. */
    public const SEPARATOR = '__';

    public function name(): string
    {
        return $this->namespace.self::SEPARATOR.$this->shortName();
    }

    public function description(): Stringable|string
    {
        return $this->tool->description();
    }

    public function schema(JsonSchema $schema): array
    {
        return $this->tool->schema($schema);
    }

    public function handle(Request $request): Stringable|string
    {
        return $this->tool->handle($request);
    }

    /** The tool this wraps, for tests and for tooling that needs the real class. */
    public function inner(): Tool
    {
        return $this->tool;
    }

    private function shortName(): string
    {
        return str(ToolNameResolver::resolve($this->tool))->snake()->toString();
    }
}
