<?php

namespace Tests\Feature;

use App\Agent\MarketingAgent;
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\Facades\Http;
use Tests\TestCase;

/**
 * Shared access, with attribution.
 *
 * Access was deliberately open: this is an internal tool and the campaigns sit
 * on shared ad accounts, so colleagues administering the same account have to
 * be able to see the same work. What is not open is the internet, and what
 * replaces the ownership check is a name on every change.
 *
 * That is no longer the default - a chat is private to whoever had it unless
 * `agent.shared_conversations` is on - because it also meant anyone signed in
 * could read and write anyone else's chat from its URL. The reasoning above
 * still holds when sharing is switched on, so these keep covering it: with the
 * setting enabled a colleague reaches the work, and an anonymous request still
 * cannot. {@see ConversationPrivacyTest} covers the private default.
 */
class ChatAccessControlTest extends TestCase
{
    use RefreshDatabase;

    protected User $owner;

    protected User $stranger;

    protected string $conversationId = 'conv-owned-0001';

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

        MarketingAgent::fake(['Noted.']);
        Http::fake();

        // These describe the shared arrangement, which is now opt-in.
        config(['agent.shared_conversations' => true]);

        $this->owner = User::factory()->create();
        $this->stranger = User::factory()->create();

        DB::table('agent_conversations')->insert([
            'id' => $this->conversationId,
            'participant_type' => $this->owner->getMorphClass(),
            'participant_id' => $this->owner->getKey(),
            'title' => 'Winter Sale',
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    public function test_a_colleague_can_open_someone_elses_conversation(): void
    {
        $this->actingAs($this->stranger)
            ->get(route('chat.show', ['conversation' => $this->conversationId]))
            ->assertOk();
    }

    public function test_the_owner_can_open_their_own_conversation(): void
    {
        $this->actingAs($this->owner)
            ->get(route('chat.show', ['conversation' => $this->conversationId]))
            ->assertOk();
    }

    public function test_a_colleague_can_send_into_someone_elses_conversation(): void
    {
        $this->actingAs($this->stranger)
            ->postJson(route('chat.send'), [
                'conversation' => $this->conversationId,
                'message' => 'change the budget to 500',
            ])
            ->assertOk();
    }

    /** Signed out is still refused, which is the boundary that remains. */
    public function test_a_guest_cannot_publish_a_campaign(): void
    {
        $campaign = Campaign::create([
            'user_id' => $this->owner->id,
            'name' => 'Winter Sale',
            'platform' => 'meta',
            'status' => 'draft',
        ]);

        $workspace = app(Workspace::class);
        $workspace->bindTo($this->conversationId);
        $workspace->produced($campaign);

        $this->postJson(route('chat.publish'), ['conversation' => $this->conversationId])
            ->assertUnauthorized();

        Http::assertNothingSent();
        $this->assertSame('draft', $campaign->fresh()->status);
    }

    public function test_a_guest_cannot_approve_a_paused_tool_call(): void
    {
        $this->postJson(route('chat.decide'), [
            'conversation' => $this->conversationId,
            'tool_call_id' => 'call_campaign__publish_campaign',
            'approved' => true,
        ])->assertUnauthorized();

        Http::assertNothingSent();
    }

    public function test_a_guest_cannot_switch_focus(): void
    {
        $campaign = Campaign::create([
            'user_id' => $this->owner->id,
            'name' => 'Winter Sale',
            'platform' => 'meta',
            'status' => 'draft',
        ]);

        $workspace = app(Workspace::class);
        $workspace->bindTo($this->conversationId);
        $workspace->produced($campaign);

        $this->postJson(route('chat.view'), [
            'conversation' => $this->conversationId,
            'campaign' => $campaign->id,
        ])->assertUnauthorized();
    }

    /** A conversation that does not exist is still a 404. */
    public function test_an_unknown_conversation_is_not_found(): void
    {
        $this->actingAs($this->stranger)
            ->get(route('chat.show', ['conversation' => 'conv-does-not-exist']))
            ->assertNotFound();
    }
}
