<?php

namespace Tests\Feature;

use App\Agent\ToolRegistry;
use App\Agent\Tools\Campaign\StartCampaign;
use App\Agent\Workspace;
use App\Models\ArtifactFieldSource;
use App\Models\Campaign;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Ai\Tools\Request;
use Tests\TestCase;

/**
 * The product never claims the buyer chose a platform they never named.
 *
 * Seen on dev on 23 Sep in a chat that reads, in full, as a request to promote
 * a URL. Meta is not mentioned anywhere in it, by the buyer or in the replies,
 * and the campaign was created on Meta regardless. That on its own is the model
 * guessing, and guessing is recoverable.
 *
 * What made it stick is that StartCampaign then recorded the platform as
 * USER_STATED unconditionally. Provenance is handed to the agent every turn as
 * where_each_value_came_from, so the agent was told the buyer had asked for
 * Meta, and from then on nothing had any reason to question it. The guess was
 * laundered into a stated fact by the line that was supposed to be tracking
 * exactly that distinction.
 *
 * The tool cannot tell a pick from a guess: choosing from the on-screen chooser
 * sends an ordinary message, which the model then turns into the same argument
 * it would have invented. So the honest record is the conservative one, and the
 * tool description is what has to stop the guess being made.
 */
class PlatformIsNotAssumedTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();

        $this->actingAs(User::factory()->create());
    }

    public function test_a_passed_platform_is_recorded_as_the_models_reading_not_the_users(): void
    {
        $created = $this->runTool('campaign__start_campaign', ['platform' => 'meta']);

        $sources = app(Workspace::class)->sourcesFor(Campaign::find($created['campaign_id']));

        $this->assertSame(
            ArtifactFieldSource::MODEL_INFERRED,
            $sources['platform'],
            'A platform argument only says the model passed it, never that the buyer asked for it.',
        );
    }

    /**
     * Omitting it still asks rather than defaulting.
     *
     * This is the path the broken chat should have taken. It already worked;
     * the test is here so that "just default to Meta, it is the connected one"
     * cannot be reintroduced quietly.
     */
    public function test_no_platform_creates_no_campaign_and_asks_instead(): void
    {
        $result = $this->runTool('campaign__start_campaign', []);

        $this->assertTrue($result['ok']);
        $this->assertSame(
            0,
            Campaign::query()->count(),
            'A campaign was created on some platform before the buyer had picked one.',
        );
    }

    /**
     * The description tells the model not to guess.
     *
     * Provenance stops the guess being believed; only the description stops it
     * being made. Asserted at the source because the alternative is a live model
     * call, which cannot be relied on to fail the same way twice.
     */
    public function test_the_tool_tells_the_model_not_to_assume_a_platform(): void
    {
        $description = (string) app(StartCampaign::class)->description();

        $this->assertStringContainsString(
            'Only pass a platform the user has actually named',
            $description,
            'Nothing tells the model to leave the platform out when it has not been told one.',
        );

        $this->assertStringContainsString(
            'do not assume Meta',
            $description,
            'Meta being the only connected platform is exactly why it gets assumed.',
        );
    }

    /** @return array<string,mixed> */
    private function runTool(string $name, array $arguments): array
    {
        foreach (app(ToolRegistry::class)->resolve() as $tool) {
            if ($tool->name() === $name) {
                return json_decode((string) $tool->handle(new Request($arguments)), true);
            }
        }

        $this->fail("No tool registered as [{$name}].");
    }
}
