<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Str;
use Laravel\Ai\Models\Conversation;
use Tests\TestCase;

/**
 * A chat belongs to the person who had it.
 *
 * Conversations were deliberately shared once: one list, everyone's work, so
 * the team could pick up each other's campaigns. The cost was not obvious from
 * the sidebar - anyone signed in could also open, and post into, anyone else's
 * chat by its URL, because nothing checked ownership on the way in.
 *
 * What these pin: the list is the user's own, the URL is not a way round that,
 * and the shared behaviour is still available as a setting rather than gone.
 */
class ConversationPrivacyTest extends TestCase
{
    use RefreshDatabase;

    protected User $me;

    protected User $someoneElse;

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

        $this->me = User::factory()->create();
        $this->someoneElse = User::factory()->create();
    }

    private function conversationFor(?User $user, string $title): Conversation
    {
        // The id is a uuid the package assigns when it creates a conversation
        // itself; made here because these tests build one directly.
        return Conversation::forceCreate([
            'id' => (string) Str::uuid7(),
            'participant_type' => $user?->getMorphClass(),
            'participant_id' => $user?->getKey(),
            'title' => $title,
        ]);
    }

    public function test_the_sidebar_lists_only_my_own_chats(): void
    {
        $this->conversationFor($this->me, 'My winter sale');
        $this->conversationFor($this->someoneElse, 'Their secret launch');

        $this->actingAs($this->me)
            ->get(route('chat.show'))
            ->assertOk()
            ->assertSee('My winter sale')
            ->assertDontSee('Their secret launch');
    }

    /**
     * The URL must not be a way round the list.
     *
     * Scoping only the sidebar would hide other people's chats while leaving
     * them perfectly readable to anyone who had the link.
     */
    public function test_i_cannot_open_someone_elses_chat_by_its_url(): void
    {
        $theirs = $this->conversationFor($this->someoneElse, 'Their secret launch');

        $this->actingAs($this->me)
            ->get(route('chat.show', ['conversation' => $theirs->id]))
            ->assertNotFound();
    }

    /** Nor post into it, which is the same door. */
    public function test_i_cannot_post_into_someone_elses_chat(): void
    {
        $theirs = $this->conversationFor($this->someoneElse, 'Their secret launch');

        $this->actingAs($this->me)
            ->post(route('chat.send'), ['message' => 'hello', 'conversation' => $theirs->id])
            ->assertNotFound();
    }

    public function test_i_can_still_open_my_own(): void
    {
        $mine = $this->conversationFor($this->me, 'My winter sale');

        $this->actingAs($this->me)
            ->get(route('chat.show', ['conversation' => $mine->id]))
            ->assertOk();
    }

    /**
     * Work from before ownership was tracked stays reachable.
     *
     * Those conversations have no participant recorded. Treating them as
     * nobody's would delete them from the product without deleting them.
     */
    public function test_chats_with_no_owner_recorded_are_still_visible(): void
    {
        $orphan = $this->conversationFor(null, 'From before we tracked this');

        $this->actingAs($this->me)
            ->get(route('chat.show', ['conversation' => $orphan->id]))
            ->assertOk();
    }

    /** The old behaviour is a setting, not a deletion. */
    public function test_sharing_can_be_turned_back_on(): void
    {
        config(['agent.shared_conversations' => true]);

        $theirs = $this->conversationFor($this->someoneElse, 'Their secret launch');

        $this->actingAs($this->me)
            ->get(route('chat.show', ['conversation' => $theirs->id]))
            ->assertOk();

        $this->actingAs($this->me)
            ->get(route('chat.show'))
            ->assertSee('Their secret launch');
    }
}
