<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tests\TestCase;

/**
 * A chat list shows your chats, wherever it is rendered.
 *
 * PR #27 added two new places that list conversations, neither scoped to the
 * user: the sidebar view composer, which renders on every page in the shell,
 * and the /chats index with its two counts. Both sat behind auth, which is not
 * the same as being behind ownership.
 *
 * The rule has to hold in every one of them at once. Scoping the list while
 * leaving the URL open, or one list and not another, is worse than scoping
 * none: it looks fixed exactly where somebody would check.
 */
class ChatListIsScopedTest extends TestCase
{
    use RefreshDatabase;

    private function conversationFor(?User $user, string $title, ?string $chatType = null): string
    {
        $id = (string) Str::uuid();

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

        return $id;
    }

    /** The /chats index lists mine and not theirs. */
    public function test_the_chats_index_lists_only_my_conversations(): void
    {
        $mine = User::factory()->create();
        $theirs = User::factory()->create();

        $this->conversationFor($mine, 'My winter sale');
        $this->conversationFor($theirs, 'Their secret launch');

        $this->actingAs($mine)
            ->get(route('chats.index'))
            ->assertOk()
            ->assertSee('My winter sale')
            ->assertDontSee('Their secret launch');
    }

    /**
     * And its counts agree with the list.
     *
     * Three separate queries had to remember the same two conditions, so the
     * count could say five while the list showed one.
     */
    public function test_the_chats_index_counts_only_my_conversations(): void
    {
        $mine = User::factory()->create();
        $theirs = User::factory()->create();

        $this->conversationFor($mine, 'Mine one');
        $this->conversationFor($theirs, 'Theirs one');
        $this->conversationFor($theirs, 'Theirs two');

        $response = $this->actingAs($mine)->get(route('chats.index'));

        $stats = $response->viewData('stats');

        $this->assertSame(1, $stats['all'], 'The count includes other people\'s chats.');
        $this->assertSame(1, $stats['today']);
    }

    /**
     * The sidebar is the one that renders everywhere.
     *
     * Checked on the dashboard rather than the chat page on purpose: the chat
     * controllers pass their own scoped list, so the composer only fills the
     * gap on pages like this one, which is exactly where it went unnoticed.
     */
    public function test_the_sidebar_on_other_pages_lists_only_my_conversations(): void
    {
        $mine = User::factory()->create();
        $theirs = User::factory()->create();

        $this->conversationFor($mine, 'My winter sale');
        $this->conversationFor($theirs, 'Their secret launch');

        $this->actingAs($mine)
            ->get(route('home'))
            ->assertOk()
            ->assertSee('My winter sale')
            ->assertDontSee('Their secret launch');
    }

    /**
     * A conversation nobody owns stays visible.
     *
     * These predate ownership being tracked. mayOpen() lets them through, so
     * the lists must too, or the list hides what the link still opens.
     */
    public function test_a_conversation_with_no_participant_is_still_listed(): void
    {
        $mine = User::factory()->create();

        $this->conversationFor(null, 'Legacy conversation');

        $this->actingAs($mine)
            ->get(route('chats.index'))
            ->assertOk()
            ->assertSee('Legacy conversation');
    }

    /**
     * The Google chat's own list is filtered on the value the column holds.
     *
     * The composer asked for chat_type 'google'; nothing writes that. It was
     * unreachable rather than broken, because GoogleChatController passes its
     * own list, but an unreachable wrong answer is still a wrong answer.
     */
    public function test_the_google_sidebar_filter_uses_the_value_the_column_holds(): void
    {
        $source = file_get_contents(app_path('Providers/AppServiceProvider.php'));

        $this->assertStringNotContainsString(
            "'chat_type', 'google')",
            $source,
            "The sidebar filters Google chats on 'google', which nothing writes.",
        );
        $this->assertStringContainsString("'chat_type', 'google_ads'", $source);
    }
}
