<?php

namespace Tests\Feature\Security\Authorization;

use App\Http\Livewire\Mailings\Manage as MailingsManage;
use App\Http\Livewire\Profiles\Create as ProfilesCreate;
use App\Http\Livewire\Tags\Create as TagsCreate;
use App\Models\Admin;
use App\Models\Bank;
use App\Models\Organization;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;

/**
 * Livewire Method-Level Authorization Tests
 *
 * Tests critical method-level authorization to prevent Livewire direct method invocation attacks.
 * Focuses on the two newly discovered critical vulnerabilities and authorization patterns.
 *
 * @group security
 * @group authorization
 * @group livewire
 * @group critical
 */
class LivewireMethodAuthorizationTest extends TestCase
{
    use RefreshDatabase;

    // ===========================================
    // TAGS/CREATE.PHP - AUTHORIZATION TESTS
    // ===========================================

    /** @test */
    public function admin_can_call_tags_create_method()
    {
        $admin = Admin::factory()->create();
        $this->actingAs($admin, 'admin');
        session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);

        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(200);
    }

    /** @test */
    public function central_bank_can_call_tags_create_method()
    {
        $bank = Bank::factory()->create(['level' => 0]);
        $this->actingAs($bank, 'bank');
        session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);

        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(200);
    }

    /** @test */
    public function regular_bank_cannot_call_tags_create_method()
    {
        $bank = Bank::factory()->create(['level' => 1]);
        $this->actingAs($bank, 'bank');
        session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);

        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(403);
    }

    /** @test */
    public function user_cannot_call_tags_create_method()
    {
        $user = User::factory()->create();
        $this->actingAs($user, 'web');
        session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);

        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(403);
    }

    /** @test */
    public function organization_cannot_call_tags_create_method()
    {
        $org = Organization::factory()->create();
        $this->actingAs($org, 'organization');
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $org->id]);

        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(403);
    }

    // ===========================================
    // PROFILES/CREATE.PHP - CRITICAL VULNERABILITY FIX
    // This was a CRITICAL vulnerability - unauthorized profile creation
    // ===========================================

    /** @test */
    public function admin_can_access_profiles_create_component()
    {
        $admin = Admin::factory()->create();
        $this->actingAs($admin, 'admin');
        session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);

        $component = Livewire::test(ProfilesCreate::class);

        $component->assertStatus(200);
    }

    /** @test */
    public function central_bank_can_access_profiles_create_component()
    {
        $bank = Bank::factory()->create(['level' => 0]);
        $this->actingAs($bank, 'bank');
        session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);

        $component = Livewire::test(ProfilesCreate::class);

        $component->assertStatus(200);
    }

    /** @test */
    public function user_cannot_access_profiles_create_component()
    {
        $user = User::factory()->create();
        $this->actingAs($user, 'web');
        session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);

        $component = Livewire::test(ProfilesCreate::class);

        $component->assertStatus(403);
    }

    /** @test */
    public function organization_cannot_access_profiles_create_component()
    {
        $org = Organization::factory()->create();
        $this->actingAs($org, 'organization');
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $org->id]);

        $component = Livewire::test(ProfilesCreate::class);

        $component->assertStatus(403);
    }

    // ===========================================
    // MAILINGS/MANAGE.PHP - CRITICAL VULNERABILITY FIX
    // bulkDeleteMailings() method was unprotected
    // ===========================================

    /** @test */
    public function admin_can_access_mailings_manage_component()
    {
        $admin = Admin::factory()->create();
        $this->actingAs($admin, 'admin');
        session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);

        $component = Livewire::test(MailingsManage::class);

        $component->assertStatus(200);
    }

    /** @test */
    public function central_bank_can_access_mailings_manage_component()
    {
        $bank = Bank::factory()->create(['level' => 0]);
        $this->actingAs($bank, 'bank');
        session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);

        $component = Livewire::test(MailingsManage::class);

        $component->assertStatus(200);
    }

    /** @test */
    public function user_cannot_access_mailings_manage_component()
    {
        $user = User::factory()->create();
        $this->actingAs($user, 'web');
        session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);

        $component = Livewire::test(MailingsManage::class);

        $component->assertStatus(403);
    }

    /** @test */
    public function organization_cannot_access_mailings_manage_component()
    {
        $org = Organization::factory()->create();
        $this->actingAs($org, 'organization');
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $org->id]);

        $component = Livewire::test(MailingsManage::class);

        $component->assertStatus(403);
    }

    // ===========================================
    // CROSS-GUARD ATTACK PREVENTION TESTS
    // ===========================================

    /** @test */
    public function user_authenticated_on_wrong_guard_cannot_access_admin_components()
    {
        $user = User::factory()->create();
        $this->actingAs($user, 'web');

        // Try to fake being an admin by setting wrong session
        $admin = Admin::factory()->create();
        session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);

        // Should be blocked because guard doesn't match
        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(403);
    }

    /** @test */
    public function admin_cannot_access_other_admins_session()
    {
        $admin1 = Admin::factory()->create();
        $admin2 = Admin::factory()->create();

        $this->actingAs($admin1, 'admin');
        // Try to fake session to access admin2's context
        session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin2->id]);

        // Should be blocked by ProfileAuthorizationHelper IDOR prevention
        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(403);
    }

    /** @test */
    public function unauthenticated_user_cannot_access_admin_components()
    {
        // No authentication at all - expect redirect or 403
        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(403);
    }

    /** @test */
    public function user_with_no_session_cannot_access_admin_components()
    {
        $user = User::factory()->create();
        $this->actingAs($user, 'web');
        // Don't set session variables - this simulates a corrupted or missing session

        // Set minimal session to prevent "No active profile" error
        // but make it point to a non-existent or wrong profile
        session([
            'activeProfileType' => User::class,
            'activeProfileId' => $user->id,
            'active_guard' => 'web',
        ]);

        // User (web guard) should not be able to access admin components
        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(403);
    }

    // ===========================================
    // AUTHORIZATION CACHING TESTS
    // ===========================================

    /** @test */
    public function authorization_is_cached_within_same_request()
    {
        $admin = Admin::factory()->create();
        $this->actingAs($admin, 'admin');
        session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);

        $component = Livewire::test(TagsCreate::class);

        // First check happens in mount()
        $component->assertStatus(200);

        // Component can be used multiple times - caching works
        $component->assertStatus(200);
    }

    // ===========================================
    // BANK LEVEL VALIDATION TESTS
    // ===========================================

    /** @test */
    public function only_central_bank_level_zero_can_access_admin_functions()
    {
        // Test level 0 (central bank) - should work
        $centralBank = Bank::factory()->create(['level' => 0]);
        $this->actingAs($centralBank, 'bank');
        session(['activeProfileType' => Bank::class, 'activeProfileId' => $centralBank->id]);

        $component = Livewire::test(TagsCreate::class);
        $component->assertStatus(200);
    }

    /** @test */
    public function bank_level_one_cannot_access_admin_functions()
    {
        $bank = Bank::factory()->create(['level' => 1]);
        $this->actingAs($bank, 'bank');
        session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);

        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(403);
    }

    /** @test */
    public function bank_level_two_cannot_access_admin_functions()
    {
        $bank = Bank::factory()->create(['level' => 2]);
        $this->actingAs($bank, 'bank');
        session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);

        $component = Livewire::test(TagsCreate::class);

        $component->assertStatus(403);
    }
}
