<?php

declare(strict_types=1);

namespace Plugin\tnt_mcp\src\Mcp\Tools;

use Plugin\tnt_mcp\src\Mcp\Contracts\Tool;
use Plugin\tnt_mcp\src\Mcp\Mode\EndpointClass;
use Plugin\tnt_mcp\src\Ai\AiConfigurationStore;
use Plugin\tnt_mcp\src\Ai\AiConnectionTester;

/**
 * READ tool: does the STORED provider configuration actually work (epic 4.3)?
 *
 * Ungated on purpose. It reveals nothing a client could not learn by trying to use the AI action,
 * it needs no key from the caller, and it is the tool that turns "the automation did not run" into
 * "the key expired" — withholding that behind the write switch would only make a broken shop harder
 * to diagnose.
 *
 * It never throws for a shop that has nothing configured: "not configured" is an answer to "does it
 * work?", and the message names what is missing.
 */
final class TestAiConnection implements Tool
{
    /** @var \Closure(): AiConfigurationStore */
    private readonly \Closure $store;

    /** @var \Closure(): AiConnectionTester */
    private readonly \Closure $tester;

    /**
     * @param \Closure(): AiConfigurationStore      $store  lazy — it resolves the shop DB
     * @param (\Closure(): AiConnectionTester)|null $tester
     */
    public function __construct(\Closure $store, ?\Closure $tester = null)
    {
        $this->store  = $store;
        $this->tester = $tester ?? static fn (): AiConnectionTester => new AiConnectionTester();
    }

    public function name(): string
    {
        return 'test_ai_connection';
    }

    public function description(): string
    {
        return 'Call the configured LLM provider with the stored key and report whether it is '
            . 'accepted. Tells an expired key from a broken workflow.';
    }

    /** @return array<string,mixed> */
    public function inputSchema(): array
    {
        return [
            'type'                 => 'object',
            // Empty array, not stdClass: the provider contract test asserts `properties` is an
            // array, and json_encode turns [] into [] rather than {} — which every MCP client
            // accepts for a no-argument tool.
            'properties'           => [],
            'additionalProperties' => false,
        ];
    }

    public function isWrite(): bool
    {
        return false;
    }

    public function scope(): string
    {
        return 'ai:read';
    }

    public function endpointClass(): EndpointClass
    {
        return EndpointClass::Reversible;
    }

    /**
     * @param array<string,mixed> $args
     *
     * @return array<string,mixed>
     */
    public function run(array $args): array
    {
        return ($this->tester)()->testStored(($this->store)())->jsonSerialize();
    }
}
