<?php

use App\Models\Permission;
use App\Models\Role;
use App\Models\User;

function makeImpersonator(): User
{
    $admin = User::factory()->create(['is_active' => true]);
    $perm = Permission::firstOrCreate(['name' => 'impersonate users', 'guard_name' => 'web']);
    $admin->givePermissionTo($perm);

    return $admin;
}

test('guest cannot start impersonation', function () {
    $target = User::factory()->create();

    $this->post("/impersonate/{$target->id}")->assertRedirect('/login');
});

test('user without permission cannot start impersonation', function () {
    $admin = User::factory()->create();
    $target = User::factory()->create();

    $this->actingAs($admin)->post("/impersonate/{$target->id}")->assertForbidden();
});

test('cannot impersonate self', function () {
    $admin = makeImpersonator();

    $this->actingAs($admin)
        ->post("/impersonate/{$admin->id}")
        ->assertForbidden();
});

test('cannot impersonate an inactive user', function () {
    $admin = makeImpersonator();
    $target = User::factory()->create(['is_active' => false]);

    $this->actingAs($admin)
        ->post("/impersonate/{$target->id}")
        ->assertForbidden();
});

test('cannot impersonate a Developer (Super Admin)', function () {
    $admin = makeImpersonator();
    $dev = User::factory()->create(['is_active' => true]);
    Role::firstOrCreate(['name' => 'Developer', 'guard_name' => 'web']);
    $dev->assignRole('Developer');

    $this->actingAs($admin)
        ->post("/impersonate/{$dev->id}")
        ->assertForbidden();
});

test('start switches the authenticated user and stashes original id', function () {
    $admin = makeImpersonator();
    $target = User::factory()->create(['is_active' => true]);

    $this->actingAs($admin)
        ->post("/impersonate/{$target->id}")
        ->assertRedirect(route('dashboard', absolute: false))
        ->assertSessionHas('impersonator_id', $admin->id);

    expect(auth()->id())->toBe($target->id);
});

test('cannot start a second impersonation while already impersonating', function () {
    $admin = makeImpersonator();
    $first = User::factory()->create(['is_active' => true]);
    $first->givePermissionTo('impersonate users'); // edge case: target also has permission
    $second = User::factory()->create(['is_active' => true]);

    $this->actingAs($admin)->post("/impersonate/{$first->id}");

    $this->post("/impersonate/{$second->id}")
        ->assertRedirect()
        ->assertSessionHas('error');

    expect(auth()->id())->toBe($first->id);
});

test('stop without an active session returns 403', function () {
    $admin = makeImpersonator();

    $this->actingAs($admin)->post('/impersonate/stop')->assertForbidden();
});

test('stop restores the original super admin', function () {
    $admin = makeImpersonator();
    $target = User::factory()->create(['is_active' => true]);

    $this->actingAs($admin)->post("/impersonate/{$target->id}");
    expect(auth()->id())->toBe($target->id);

    $this->post('/impersonate/stop')
        ->assertRedirect(route('users', absolute: false));

    expect(auth()->id())->toBe($admin->id);
    expect(session()->has('impersonator_id'))->toBeFalse();
});
