<?php

namespace Tests\Feature;

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

/**
 * Asking for a new campaign never edits the published one.
 *
 * start_campaign updates an existing campaign for the platform rather than
 * making a second, which is right while that campaign is a draft: it is how
 * re-entering the flow keeps working on the thing in hand. It ran for a live
 * campaign too.
 *
 * Mohsin typed "create campaing" on 28 Sep. Campaign 120250886412960429 was
 * already on Meta. The tool renamed it, then renamed it back, and the chat said
 * so: "It briefly changed its working name, which I've restored; nothing was
 * sent to Meta." Nothing did reach Meta, which is luck rather than design - for
 * the length of that turn our name and Meta's disagreed, and push_changes in
 * between would have made the accident permanent on a live campaign.
 *
 * Creating a second campaign on one platform in one conversation is a real gap.
 * Quietly editing the live one is not a smaller version of it.
 */
class APublishedCampaignIsNotRenamedByAccidentTest extends TestCase
{
    use RefreshDatabase;

    private function published(): Campaign
    {
        $campaign = Campaign::create([
            'user_id' => auth()->id(),
            'name' => 'Browse the Web Without Ads & Trackers - Meta',
            'platform' => 'meta',
            'status' => 'published',
            'objective' => 'OUTCOME_LEADS',
            'external_campaign_id' => '120250886412960429',
        ]);

        app(Workspace::class)->produced($campaign);

        return $campaign;
    }

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

        $this->actingAs(User::factory()->create());
        app(Workspace::class)->bindTo('conv-second-campaign');
    }

    private function start(array $arguments): array
    {
        $result = collect(app(ToolRegistry::class)->resolve())
            ->first(fn ($t) => $t->name() === 'campaign__start_campaign')
            ->handle(new Request($arguments));

        return json_decode((string) $result, true);
    }

    /** The defect: the live campaign's name was overwritten. */
    public function test_a_published_campaign_is_not_renamed(): void
    {
        $campaign = $this->published();
        $before = $campaign->name;

        $this->start(['name' => 'Something Completely Different', 'platform' => 'meta']);

        $this->assertSame($before, $campaign->refresh()->name, 'the published campaign was renamed');
    }

    /** Nor re-objectived. */
    public function test_a_published_campaign_keeps_its_objective(): void
    {
        $campaign = $this->published();

        $this->start(['platform' => 'meta', 'objective' => 'OUTCOME_TRAFFIC']);

        $this->assertSame('OUTCOME_LEADS', $campaign->refresh()->objective);
    }

    /** And the refusal names what exists rather than reporting a success. */
    public function test_the_refusal_says_what_is_already_there(): void
    {
        $this->published();

        $result = $this->start(['name' => 'Second one', 'platform' => 'meta']);

        $this->assertFalse($result['ok']);
        $this->assertStringContainsString('not supported yet', $result['error']);
        $this->assertSame('120250886412960429', $result['existing'][0]['external_campaign_id']);
    }

    /**
     * A draft is still updated, which is what this branch is for.
     *
     * Refusing here too would break re-entering the flow on a campaign being
     * built, which is the ordinary case.
     */
    public function test_a_draft_campaign_is_still_updated(): void
    {
        $campaign = Campaign::create([
            'user_id' => auth()->id(),
            'name' => 'Working title',
            'platform' => 'meta',
            'status' => 'draft',
        ]);

        app(Workspace::class)->produced($campaign);

        $result = $this->start(['name' => 'A better name', 'platform' => 'meta']);

        $this->assertTrue($result['ok'], $result['error'] ?? '');
        $this->assertSame('A better name', $campaign->refresh()->name);
    }

    /**
     * A second platform is still started when one is already live.
     *
     * Only the live platform is skipped, so a Meta campaign already published
     * does not stop a Google one being created beside it.
     */
    public function test_another_platform_is_still_created(): void
    {
        $meta = $this->published();

        $result = $this->start(['platform' => 'google', 'name' => 'Google one']);

        $this->assertTrue($result['ok'], $result['error'] ?? '');
        $this->assertSame('Browse the Web Without Ads & Trackers - Meta', $meta->refresh()->name);
        $this->assertSame('google', Campaign::where('platform', 'google')->sole()->platform);
    }
}
