<?php

namespace Tests\Feature;

use App\Agent\Workspace;
use App\Models\Campaign;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Laravel\Ai\Models\Conversation;
use Tests\TestCase;

/**
 * Clicking another campaign's tab has to open that campaign.
 *
 * Found in the browser on 21 Sep: every click on the switcher answered 404 and
 * the panel stayed on the campaign it opened with. The request sends "14" and
 * the `integer` validation rule checks the shape without casting, so comparing
 * it to a cast id with === was false for every row in the conversation.
 *
 * Nothing caught it because the switcher only appears with more than one
 * campaign in a conversation, which nothing could produce until multi-platform.
 */
class CampaignSwitcherTest extends TestCase
{
    use RefreshDatabase;

    /** The id is a uuid the table does not generate, so it is written directly. */
    private function conversationFor(User $user): Conversation
    {
        $id = (string) Str::uuid();

        DB::table('agent_conversations')->insert([
            'id' => $id,
            'participant_type' => $user->getMorphClass(),
            'participant_id' => $user->getKey(),
            'title' => 'Two platforms',
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        return Conversation::findOrFail($id);
    }

    public function test_focusing_another_campaign_in_the_conversation_switches_to_it(): void
    {
        $user = User::factory()->create();

        $conversation = $this->conversationFor($user);

        $workspace = app(Workspace::class);
        $workspace->bindTo($conversation->id);
        $workspace->ownedBy($user);

        $meta = Campaign::create([
            'user_id' => $user->id, 'name' => 'Meta one', 'platform' => 'meta', 'status' => 'draft',
        ]);
        $google = Campaign::create([
            'user_id' => $user->id, 'name' => 'Google one', 'platform' => 'google', 'status' => 'draft',
        ]);

        $workspace->produced($meta);
        $workspace->produced($google);
        $workspace->focusOn($google);

        // As a string, because the browser sends FormData and every value in it
        // is text. Posting a real integer here is what made an earlier version
        // of this test pass against the bug it was written to catch.
        $response = $this->actingAs($user)->post(route('chat.view'), [
            'conversation' => $conversation->id,
            'campaign' => (string) $meta->id,
        ]);

        $response->assertOk();

        // The panel shows the one that was clicked.
        $this->assertStringContainsString('Meta one', $response->json('panelHtml'));

        // And the conversation is still working on the one that was not.
        // Clicking used to call focusOn(), so a look retargeted every tool that
        // acts on the focus, which is 25 of the 27. Shyam, 23 Sep: "a user
        // isn't aware of the code design decision, he might just click
        // unknowingly that his click will affect the answer he is going to
        // enter next."
        $workspace->bindTo($conversation->id);
        $this->assertSame(
            $google->id,
            $workspace->focus()?->id,
            'Looking at a campaign changed which one the next answer lands on.',
        );
    }

    /** And the panel says so, so nobody answers believing otherwise. */
    public function test_the_panel_names_the_campaign_being_worked_on(): void
    {
        $user = User::factory()->create();
        $conversation = $this->conversationFor($user);

        $workspace = app(Workspace::class);
        $workspace->bindTo($conversation->id);
        $workspace->ownedBy($user);

        $meta = Campaign::create([
            'user_id' => $user->id, 'name' => 'Meta one', 'platform' => 'meta', 'status' => 'draft',
        ]);
        $google = Campaign::create([
            'user_id' => $user->id, 'name' => 'Google one', 'platform' => 'google', 'status' => 'draft',
        ]);

        $workspace->produced($meta);
        $workspace->produced($google);
        $workspace->focusOn($google);

        $looking = $this->actingAs($user)->post(route('chat.view'), [
            'conversation' => $conversation->id,
            'campaign' => (string) $meta->id,
        ]);

        $this->assertSame('Google one', $looking->json('workingOn'));

        // Looking at the one already in focus says nothing, because there is
        // nothing to warn about.
        $same = $this->actingAs($user)->post(route('chat.view'), [
            'conversation' => $conversation->id,
            'campaign' => (string) $google->id,
        ]);

        $this->assertNull($same->json('workingOn'));
    }

    /** A campaign in someone else's conversation is still not reachable. */
    public function test_a_campaign_outside_the_conversation_is_refused(): void
    {
        $user = User::factory()->create();

        $conversation = $this->conversationFor($user);

        $workspace = app(Workspace::class);
        $workspace->bindTo($conversation->id);
        $workspace->ownedBy($user);

        $mine = Campaign::create([
            'user_id' => $user->id, 'name' => 'Mine', 'platform' => 'meta', 'status' => 'draft',
        ]);
        $workspace->produced($mine);

        $theirs = Campaign::create([
            'user_id' => User::factory()->create()->id,
            'name' => 'Theirs', 'platform' => 'meta', 'status' => 'draft',
        ]);

        $this->actingAs($user)->post(route('chat.view'), [
            'conversation' => $conversation->id,
            'campaign' => (string) $theirs->id,
        ])->assertNotFound();
    }
}
