<?php

declare(strict_types=1);

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

uses(RefreshDatabase::class);

beforeEach(function () {
    $this->seed();
});

test('unauthorized users cannot view or manage roles and permissions', function () {
    $user = User::where('email', 'user@example.com')->first();
    
    $this->actingAs($user)
        ->get(route('rbac.index'))
        ->assertStatus(403);
});

test('authorized users can view rbac dashboard', function () {
    $admin = User::where('email', 'admin@example.com')->first();
    
    $this->actingAs($admin)
        ->get(route('rbac.index'))
        ->assertOk();
});

test('authorized users can create a new security role', function () {
    $admin = User::where('email', 'admin@example.com')->first();

    $this->actingAs($admin)
        ->post(route('rbac.store'), [
            'name' => 'Custom Role',
        ])
        ->assertRedirect()
        ->assertSessionHas('success', 'Security role created successfully.');

    $role = Role::where('name', 'Custom Role')->first();
    expect($role)->not->toBeNull();

    // Verify activity logged
    $this->assertDatabaseHas('activity_log', [
        'description' => 'Created security role: Custom Role',
        'causer_id' => $admin->id,
        'subject_id' => $role->id,
    ]);
});

test('authorized users can sync permissions to a custom role', function () {
    $admin = User::where('email', 'admin@example.com')->first();
    $role = Role::create(['name' => 'Editor']);

    $this->actingAs($admin)
        ->put(route('rbac.update', $role->id), [
            'name' => 'Editor',
            'permissions' => ['view dashboard', 'view logs'],
        ])
        ->assertRedirect()
        ->assertSessionHas('success', 'Role settings updated successfully.');

    $role->refresh();
    expect($role->hasPermissionTo('view dashboard'))->toBeTrue();
    expect($role->hasPermissionTo('view logs'))->toBeTrue();
    expect($role->hasPermissionTo('manage settings'))->toBeFalse();

    // Verify activity logged
    $this->assertDatabaseHas('activity_log', [
        'description' => 'Updated permissions for role: Editor',
        'causer_id' => $admin->id,
        'subject_id' => $role->id,
    ]);
});

test('protected system roles cannot be renamed or deleted', function () {
    $admin = User::where('email', 'admin@example.com')->first();
    
    $superAdminRole = Role::where('name', 'Super Admin')->first();
    $userRole = Role::where('name', 'User')->first();

    // Rename Super Admin attempt
    $this->actingAs($admin)
        ->put(route('rbac.update', $superAdminRole->id), [
            'name' => 'Renamed Super Admin',
            'permissions' => [],
        ])
        ->assertRedirect()
        ->assertSessionHas('error', 'The Super Admin role name cannot be modified.');

    // Delete system role attempt
    $this->actingAs($admin)
        ->delete(route('rbac.destroy', $userRole->id))
        ->assertRedirect()
        ->assertSessionHas('error', "System role 'User' is protected and cannot be deleted.");

    expect(Role::where('name', 'User')->exists())->toBeTrue();
});

test('super admin permissions are locked and cannot be updated', function () {
    $admin = User::where('email', 'admin@example.com')->first();
    $superAdminRole = Role::where('name', 'Super Admin')->first();

    $this->actingAs($admin)
        ->put(route('rbac.update', $superAdminRole->id), [
            'name' => 'Super Admin',
            'permissions' => ['view dashboard'], // attempt to restrict
        ])
        ->assertRedirect()
        ->assertSessionHas('error', 'Super Admin permissions are locked and cannot be customized.');
});

test('authorized users can create a new permission', function () {
    $admin = User::where('email', 'admin@example.com')->first();

    $this->actingAs($admin)
        ->post(route('rbac.permissions.store'), [
            'name' => 'publish posts',
        ])
        ->assertRedirect()
        ->assertSessionHas('success', 'Security permission created successfully.');

    $permission = Permission::where('name', 'publish posts')->first();
    expect($permission)->not->toBeNull();

    // Verify activity logged
    $this->assertDatabaseHas('activity_log', [
        'description' => 'Created security permission: publish posts',
        'causer_id' => $admin->id,
        'subject_id' => $permission->id,
    ]);
});

test('authorized users can rename a custom permission', function () {
    $admin = User::where('email', 'admin@example.com')->first();
    $permission = Permission::create(['name' => 'original permission', 'guard_name' => 'web']);

    $this->actingAs($admin)
        ->put(route('rbac.permissions.update', $permission->id), [
            'name' => 'renamed permission',
        ])
        ->assertRedirect()
        ->assertSessionHas('success', 'Security permission renamed successfully.');

    $permission->refresh();
    expect($permission->name)->toBe('renamed permission');

    // Verify activity logged
    $this->assertDatabaseHas('activity_log', [
        'description' => 'Updated security permission: original permission to renamed permission',
        'causer_id' => $admin->id,
        'subject_id' => $permission->id,
    ]);
});

test('authorized users cannot rename or delete core system permissions', function () {
    $admin = User::where('email', 'admin@example.com')->first();
    $systemPermission = Permission::where('name', 'manage settings')->first();
    expect($systemPermission)->not->toBeNull();

    // Rename attempt
    $this->actingAs($admin)
        ->put(route('rbac.permissions.update', $systemPermission->id), [
            'name' => 'hacked settings',
        ])
        ->assertRedirect()
        ->assertSessionHas('error', 'Core system permissions are protected and cannot be renamed.');

    // Delete attempt
    $this->actingAs($admin)
        ->delete(route('rbac.permissions.destroy', $systemPermission->id))
        ->assertRedirect()
        ->assertSessionHas('error', "Core system permission 'manage settings' is protected and cannot be deleted.");

    expect(Permission::where('name', 'manage settings')->exists())->toBeTrue();
});

test('authorized users can delete a custom permission', function () {
    $admin = User::where('email', 'admin@example.com')->first();
    $permission = Permission::create(['name' => 'custom delete', 'guard_name' => 'web']);

    $this->actingAs($admin)
        ->delete(route('rbac.permissions.destroy', $permission->id))
        ->assertRedirect()
        ->assertSessionHas('success', 'Security permission deleted successfully.');

    expect(Permission::where('id', $permission->id)->exists())->toBeFalse();

    // Verify activity logged
    $this->assertDatabaseHas('activity_log', [
        'description' => 'Deleted security permission: custom delete',
        'causer_id' => $admin->id,
    ]);
});
