<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

class HeaderSearchControllerTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        // Reset Spatie permission cache and create required roles
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
        foreach (['Super Manager', 'Manager', 'Members', 'Trainers', 'Trainees',
                  'Mentor', 'Mentee', 'Partners', 'Contributor', 'Health Marketor'] as $role) {
            Role::firstOrCreate(['name' => $role, 'guard_name' => 'web']);
        }
    }

    // -------------------------------------------------------------------------
    // Authentication
    // -------------------------------------------------------------------------

    public function test_unauthenticated_request_returns_unauthorized(): void
    {
        $response = $this->getJson('/api/header/search?q=test');
        $response->assertUnauthorized();
    }

    // -------------------------------------------------------------------------
    // Validation — Requirement 4.1 / 10.5
    // -------------------------------------------------------------------------

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

        $response = $this->actingAs($user)->getJson('/api/header/search');
        $response->assertUnprocessable();
    }

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

        $response = $this->actingAs($user)->getJson('/api/header/search?q=a');
        $response->assertUnprocessable();
    }

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

        $response = $this->actingAs($user)->getJson('/api/header/search?q=');
        $response->assertUnprocessable();
    }

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

        $q = str_repeat('a', 101);
        $response = $this->actingAs($user)->getJson("/api/header/search?q={$q}");
        $response->assertUnprocessable();
    }

    // -------------------------------------------------------------------------
    // Response structure — Requirement 4.3
    // -------------------------------------------------------------------------

    public function test_valid_query_returns_correct_structure(): void
    {
        $user = User::factory()->create();
        $user->assignRole('Super Manager');

        $response = $this->actingAs($user)->getJson('/api/header/search?q=test');

        $response->assertOk()
            ->assertJsonStructure([
                'results',
                'total',
            ]);

        $this->assertIsInt($response->json('total'));
        $this->assertIsArray($response->json('results'));
    }

    public function test_user_with_no_role_returns_empty_results(): void
    {
        $user = User::factory()->create();
        // No role assigned

        $response = $this->actingAs($user)->getJson('/api/header/search?q=test');

        $response->assertOk();
        $this->assertSame(0, $response->json('total'));
        $this->assertEmpty($response->json('results'));
    }

    // -------------------------------------------------------------------------
    // Role scoping — Requirement 4.2, 4.10
    // -------------------------------------------------------------------------

    /**
     * Super Manager scope includes Users — verify result items have required fields.
     */
    public function test_super_manager_search_returns_valid_result_items(): void
    {
        $user = User::factory()->create(['name' => 'Searchable Person']);
        $user->assignRole('Super Manager');

        $response = $this->actingAs($user)->getJson('/api/header/search?q=Searchable');

        $response->assertOk();

        $results = $response->json('results');

        // If any results returned, each item must have the required fields
        foreach ($results as $type => $items) {
            foreach ($items as $item) {
                $this->assertArrayHasKey('id', $item);
                $this->assertArrayHasKey('title', $item);
                $this->assertArrayHasKey('url', $item);
                $this->assertArrayHasKey('type', $item);
            }
        }
    }

    /**
     * Members role should NOT return Users in results (outside their scope).
     */
    public function test_members_role_does_not_return_users_type(): void
    {
        $user = User::factory()->create(['name' => 'Searchable Member User']);
        $user->assignRole('Members');

        $response = $this->actingAs($user)->getJson('/api/header/search?q=Searchable');

        $response->assertOk();

        $results = $response->json('results');
        $this->assertArrayNotHasKey('Users', $results);
    }

    /**
     * Contributor role should NOT return Users or Training Packages.
     */
    public function test_contributor_role_does_not_return_out_of_scope_types(): void
    {
        $user = User::factory()->create(['name' => 'Contributor User']);
        $user->assignRole('Contributor');

        $response = $this->actingAs($user)->getJson('/api/header/search?q=Contributor');

        $response->assertOk();

        $results = $response->json('results');
        $this->assertArrayNotHasKey('Users', $results);
        $this->assertArrayNotHasKey('Training Packages', $results);
        $this->assertArrayNotHasKey('Loan Applications', $results);
    }
}
