<?php

namespace Tests\Feature;

use App\Models\CallbackRequest;
use App\Models\Contact;
use App\Models\Conversation;
use App\Models\Membership;
use App\Models\Message;
use App\Models\Organization;
use App\Models\UnknownQuestion;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class RbacEnforcementTest extends TestCase
{
    use RefreshDatabase;

    public function test_member_without_customize_widget_cannot_update_appearance(): void
    {
        [$user] = $this->workspaceUser(['view_inbox']);

        $response = $this->actingAs($user)->put(route('settings.appearance.update'), []);

        $response->assertForbidden();
    }

    public function test_member_without_manage_channels_cannot_update_channel_settings(): void
    {
        [$user] = $this->workspaceUser(['view_inbox']);

        $response = $this->actingAs($user)->put(route('settings.channels.update', 'facebook'), []);

        $response->assertForbidden();
    }

    public function test_member_without_view_inbox_cannot_open_conversation(): void
    {
        [$user, $organization] = $this->workspaceUser([]);
        $conversation = $this->conversationFor($organization);

        $response = $this->actingAs($user)->get(route('conversations.show', $conversation));

        $response->assertForbidden();
    }

    public function test_member_without_reply_privilege_cannot_send_human_reply(): void
    {
        [$user, $organization] = $this->workspaceUser(['view_inbox']);
        $conversation = $this->conversationFor($organization);

        $response = $this->actingAs($user)->post(route('conversations.messages.store', $conversation), [
            'body' => 'I should not be able to send this.',
        ]);

        $response->assertForbidden();
        $this->assertDatabaseMissing('messages', [
            'conversation_id' => $conversation->id,
            'body' => 'I should not be able to send this.',
        ]);
    }

    public function test_member_without_train_ai_cannot_resolve_unknown_question(): void
    {
        [$user, $organization] = $this->workspaceUser(['monitor_ai']);
        $conversation = $this->conversationFor($organization);
        $message = Message::factory()->create([
            'conversation_id' => $conversation->id,
            'sender_type' => 'customer',
        ]);
        $unknownQuestion = UnknownQuestion::factory()->create([
            'organization_id' => $organization->id,
            'conversation_id' => $conversation->id,
            'contact_id' => $conversation->contact_id,
            'message_id' => $message->id,
            'status' => 'open',
        ]);

        $response = $this->actingAs($user)->post(route('unknown-questions.resolve', $unknownQuestion));

        $response->assertForbidden();
        $this->assertSame('open', $unknownQuestion->refresh()->status);
    }

    public function test_member_without_manage_callbacks_cannot_complete_callback(): void
    {
        [$user, $organization] = $this->workspaceUser(['view_inbox']);
        $conversation = $this->conversationFor($organization);
        $callbackRequest = CallbackRequest::factory()->create([
            'organization_id' => $organization->id,
            'conversation_id' => $conversation->id,
            'contact_id' => $conversation->contact_id,
            'status' => 'requested',
        ]);

        $response = $this->actingAs($user)->post(route('callback-requests.complete', $callbackRequest), [
            'notes' => 'not allowed',
        ]);

        $response->assertForbidden();
        $this->assertSame('requested', $callbackRequest->refresh()->status);
    }

    /**
     * @param  list<string>  $privileges
     * @return array{0: User, 1: Organization, 2: Membership}
     */
    private function workspaceUser(array $privileges): array
    {
        $user = User::factory()->create();
        $organization = Organization::factory()->create();
        $membership = Membership::factory()->create([
            'organization_id' => $organization->id,
            'user_id' => $user->id,
            'role' => 'agent',
            'privileges' => $privileges,
        ]);

        return [$user, $organization, $membership];
    }

    private function conversationFor(Organization $organization): Conversation
    {
        $contact = Contact::factory()->create([
            'organization_id' => $organization->id,
        ]);

        return Conversation::factory()->create([
            'organization_id' => $organization->id,
            'contact_id' => $contact->id,
        ]);
    }
}
