<?php

namespace Tests\Feature\Security\Authorization;

use App\Models\User;
use App\Models\Organization;
use App\Models\Bank;
use App\Models\Admin;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;

/**
 * Profile Deletion Authorization Tests
 *
 * Tests that users can only delete their own profiles and cannot delete
 * profiles they don't own or have access to.
 *
 * @group security
 * @group authorization
 * @group critical
 */
class ProfileDeletionAuthorizationTest extends TestCase
{
    use RefreshDatabase;

    /**
     * Test user cannot delete another user's profile
     *
     * @test
     */
    public function user_cannot_delete_another_users_profile()
    {
        // Arrange: Create two users
        $user1 = User::factory()->create(['password' => bcrypt('password123')]);
        $user2 = User::factory()->create();

        // Act: Login as user1 and try to delete user2's profile
        $this->actingAs($user1);

        // Create session as if user1 is trying to delete user2
        session(['activeProfileType' => 'App\\Models\\User']);
        session(['activeProfileId' => $user2->id]); // Malicious attempt
        session(['active_guard' => 'web']);

        // Attempt deletion
        $response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
            ->set('password', 'password123')
            ->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard());

        // Assert: The operation should fail or delete user1 (not user2)
        $this->assertDatabaseHas('users', [
            'id' => $user2->id,
            'deleted_at' => null,
        ]);
    }

    /**
     * Test user cannot delete organization they don't have access to
     *
     * @test
     */
    public function user_cannot_delete_organization_they_dont_own()
    {
        // Arrange: Create user and two organizations
        $user = User::factory()->create(['password' => bcrypt('password123')]);
        $org1 = Organization::factory()->create(['password' => bcrypt('orgpass123')]);
        $org2 = Organization::factory()->create();

        // Link user to org1 only
        $user->organizations()->attach($org1->id);

        // Act: Login as user and try to delete org2
        $this->actingAs($user);

        session(['activeProfileType' => 'App\\Models\\Organization']);
        session(['activeProfileId' => $org2->id]); // Malicious attempt
        session(['active_guard' => 'organization']);

        // Attempt deletion
        $response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
            ->set('password', 'password123')
            ->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard('organization'));

        // Assert: org2 should NOT be deleted
        $this->assertDatabaseHas('organizations', [
            'id' => $org2->id,
            'deleted_at' => null,
        ]);
    }

    /**
     * Test central bank (level 0) cannot be deleted
     *
     * @test
     */
    public function central_bank_cannot_be_deleted()
    {
        // Arrange: Create central bank
        $centralBank = Bank::factory()->create([
            'level' => 0,
            'password' => bcrypt('bankpass123')
        ]);

        $user = User::factory()->create();
        $user->banks()->attach($centralBank->id);

        // Act: Login and try to delete central bank
        $this->actingAs($user);
        auth()->guard('bank')->login($centralBank);

        session(['activeProfileType' => 'App\\Models\\Bank']);
        session(['activeProfileId' => $centralBank->id]);
        session(['active_guard' => 'bank']);

        // Attempt deletion
        $response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
            ->set('password', 'bankpass123')
            ->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard('bank'));

        // Assert: Deletion should fail with validation error
        $response->assertHasErrors(['password']);

        // Assert: Central bank still exists
        $this->assertDatabaseHas('banks', [
            'id' => $centralBank->id,
            'level' => 0,
            'deleted_at' => null,
        ]);
    }

    /**
     * Test final admin cannot be deleted
     *
     * @test
     */
    public function final_admin_cannot_be_deleted()
    {
        // Arrange: Create single admin
        $admin = Admin::factory()->create(['password' => bcrypt('adminpass123')]);
        $user = User::factory()->create();
        $user->admins()->attach($admin->id);

        // Act: Login and try to delete the only admin
        $this->actingAs($user);
        auth()->guard('admin')->login($admin);

        session(['activeProfileType' => 'App\\Models\\Admin']);
        session(['activeProfileId' => $admin->id]);
        session(['active_guard' => 'admin']);

        // Attempt deletion
        $response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
            ->set('password', 'adminpass123')
            ->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard('admin'));

        // Assert: Deletion should fail with validation error
        $response->assertHasErrors(['password']);

        // Assert: Admin still exists
        $this->assertDatabaseHas('admins', [
            'id' => $admin->id,
            'deleted_at' => null,
        ]);
    }

    /**
     * Test user can delete their own profile with correct password
     *
     * @test
     */
    public function user_can_delete_own_profile_with_correct_password()
    {
        // Arrange: Create user
        $user = User::factory()->create(['password' => bcrypt('password123')]);

        // Act: Login and delete own profile
        $this->actingAs($user);

        session(['activeProfileType' => 'App\\Models\\User']);
        session(['activeProfileId' => $user->id]);
        session(['active_guard' => 'web']);

        // Attempt deletion with correct password
        $response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
            ->set('password', 'password123')
            ->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard());

        // Assert: User is soft-deleted
        $this->assertSoftDeleted('users', [
            'id' => $user->id,
        ]);
    }

    /**
     * Test user cannot delete profile with wrong password
     *
     * @test
     */
    public function user_cannot_delete_profile_with_wrong_password()
    {
        // Arrange: Create user
        $user = User::factory()->create(['password' => bcrypt('password123')]);

        // Act: Login and try to delete with wrong password
        $this->actingAs($user);

        session(['activeProfileType' => 'App\\Models\\User']);
        session(['activeProfileId' => $user->id]);
        session(['active_guard' => 'web']);

        // Attempt deletion with wrong password
        $response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class)
            ->set('password', 'wrongpassword')
            ->call('deleteUser', request(), app(\Laravel\Jetstream\Contracts\DeletesUsers::class), auth()->guard());

        // Assert: Deletion should fail with validation error
        $response->assertHasErrors(['password']);

        // Assert: User still exists
        $this->assertDatabaseHas('users', [
            'id' => $user->id,
            'deleted_at' => null,
        ]);
    }

    /**
     * Test unauthenticated user cannot access delete form
     *
     * @test
     */
    public function unauthenticated_user_cannot_access_delete_form()
    {
        // Act: Try to render delete form without authentication
        $response = Livewire::test(\App\Http\Livewire\Profile\DeleteUserForm::class);

        // Assert: Should fail (Laravel's auth middleware should prevent this)
        // This test verifies the component requires authentication
        $this->assertGuest();
    }
}
