<?php

namespace Tests\Feature;

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

/**
 * A second, unrelated campaign does not join the first one's brief.
 *
 * StartCampaign withholds the brief deliberately: a campaign started later in
 * the same conversation is a different thing being advertised, and a brief
 * carries the landing page, the dates and a budget meant to be split. Joining
 * one would make two unrelated campaigns share money.
 *
 * The rule was written and then undone sixty lines later. Withheld and absent
 * both left $brief null, the orphan record could not tell them apart, and
 * settle() adopted the campaign into the first brief anyway.
 *
 * Absent is the first message of a new chat, where the conversation does not
 * exist yet and the campaign must join as soon as it does. Withheld is the
 * opposite instruction. They need opposite treatment, which is why the flag
 * exists rather than a null check.
 */
class AnUnrelatedCampaignKeepsItsOwnBriefTest extends TestCase
{
    use RefreshDatabase;

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

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

        $workspace = app(Workspace::class);
        $workspace->bindTo('conv-unrelated-brief');
        $workspace->ownedBy(auth()->user());
    }

    private function start(string $platform): Campaign
    {
        $result = json_decode((string) collect(app(ToolRegistry::class)->resolve())
            ->first(fn ($t) => $t->name() === 'campaign__start_campaign')
            ->handle(new Request(['platform' => $platform])), true);

        return Campaign::findOrFail($result['campaign_id']);
    }

    public function test_a_campaign_started_later_is_not_adopted_into_the_first_brief(): void
    {
        $first = $this->start('meta');

        // The brief exists and owns the first campaign from here on.
        app(Briefs::class)->attach($first);
        $this->assertNotNull($first->fresh()->brief_id, 'Precondition: the first campaign has a brief.');

        $second = $this->start('google');

        // The turn ends. This is where the adoption used to happen.
        app(Briefs::class)->settle();

        $this->assertNull(
            $second->fresh()->brief_id,
            'An unrelated campaign was adopted into the first campaign\'s brief.',
        );
    }

    /** And so it does not inherit the money either, which is the reason. */
    public function test_it_does_not_inherit_the_first_briefs_budget(): void
    {
        $first = $this->start('meta');
        $brief = app(Briefs::class)->attach($first);
        $brief->update(['budget' => 50, 'budget_mode' => 'daily']);

        $second = $this->start('google');
        app(Briefs::class)->settle();

        // ResolvesFromBrief falls back to the brief for a campaign that has
        // one, so an adopted campaign would silently read 50 here.
        $this->assertNull($second->fresh()->budget, 'An unrelated campaign inherited a shared budget.');
    }

    /**
     * The other half, unchanged: on a first message there is no conversation
     * yet, so the campaign genuinely has nowhere to go and must be adopted once
     * there is. Withholding and absence must not be confused in either
     * direction.
     */
    public function test_a_first_message_campaign_is_still_adopted(): void
    {
        $workspace = app(Workspace::class);
        $workspace->bindTo('');

        $campaign = $this->start('meta');

        $this->assertNull($campaign->brief_id, 'Precondition: nowhere to record it yet.');

        $workspace->bindTo('conv-unrelated-brief-2');
        $workspace->ownedBy(auth()->user());

        app(Briefs::class)->settle();

        $this->assertNotNull(
            $campaign->fresh()->brief_id,
            'A campaign created before the conversation existed was never adopted.',
        );
    }
}
