<?php

declare(strict_types=1);

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Auth;

uses(RefreshDatabase::class);

test('super admin can start impersonating normal user', function (): void {
    $admin = User::factory()->superAdmin()->create();
    $targetUser = User::factory()->normalUser()->create();

    Auth::login($admin);

    $response = $this->post(route('impersonation.start', $targetUser));

    $response->assertRedirect(route('dashboard'));
    expect(app(\App\Services\ImpersonationService::class)->isImpersonating())->toBeTrue();

    $this->assertDatabaseHas('impersonation_logs', [
        'admin_id' => $admin->id,
        'target_user_id' => $targetUser->id,
        'status' => 'active',
    ]);
});

test('normal user cannot start impersonation', function (): void {
    $normalUser = User::factory()->normalUser()->create();
    $targetUser = User::factory()->normalUser()->create();

    Auth::login($normalUser);

    $response = $this->post(route('impersonation.start', $targetUser));

    $response->assertRedirect();
    expect(app(\App\Services\ImpersonationService::class)->isImpersonating())->toBeFalse();
});

test('super admin cannot impersonate another super admin', function (): void {
    $admin = User::factory()->superAdmin()->create();
    $targetAdmin = User::factory()->superAdmin()->create();

    Auth::login($admin);

    $response = $this->post(route('impersonation.start', $targetAdmin));

    $response->assertRedirect();
    expect(app(\App\Services\ImpersonationService::class)->isImpersonating())->toBeFalse();
});

test('can stop active impersonation', function (): void {
    $admin = User::factory()->superAdmin()->create();
    $targetUser = User::factory()->normalUser()->create();
    $impersonationService = app(\App\Services\ImpersonationService::class);

    // Start impersonation
    Auth::login($admin);
    $impersonationService->startImpersonation($admin, $targetUser, request());
    Auth::login($targetUser);

    expect($impersonationService->isImpersonating())->toBeTrue();

    $response = $this->post(route('impersonation.stop'));

    $response->assertRedirect(\Filament\Pages\Dashboard::getUrl());
    expect($impersonationService->isImpersonating())->toBeFalse();

    $this->assertDatabaseHas('impersonation_logs', [
        'admin_id' => $admin->id,
        'target_user_id' => $targetUser->id,
        'status' => 'completed',
    ]);
});

test('stop impersonation when not impersonating redirects to admin', function (): void {
    $admin = User::factory()->superAdmin()->create();

    Auth::login($admin);

    $response = $this->post(route('impersonation.stop'));

    $response->assertRedirect(\Filament\Pages\Dashboard::getUrl());
});

test('impersonation status endpoint returns correct data', function (): void {
    $admin = User::factory()->superAdmin()->create();
    $targetUser = User::factory()->normalUser()->create();
    $impersonationService = app(\App\Services\ImpersonationService::class);

    // Test when not impersonating
    Auth::login($admin);

    $response = $this->get(route('impersonation.status'));

    $response->assertJson([
        'is_impersonating' => false,
    ]);

    // Test when impersonating
    $impersonationService->startImpersonation($admin, $targetUser, request());
    Auth::login($targetUser);

    $response = $this->get(route('impersonation.status'));

    $response->assertJson([
        'is_impersonating' => true,
        'impersonator' => [
            'name' => $admin->name,
            'email' => $admin->email,
        ],
        'target' => [
            'name' => $targetUser->name,
            'email' => $targetUser->email,
        ],
    ]);
    $response->assertJsonStructure([
        'is_impersonating',
        'impersonator',
        'target',
        'remaining_minutes',
        'expires_soon',
    ]);
});

test('unauthenticated user cannot access impersonation routes', function (): void {
    $targetUser = User::factory()->normalUser()->create();

    $response = $this->post(route('impersonation.start', $targetUser));
    $response->assertRedirect('/login');

    $response = $this->post(route('impersonation.stop'));
    $response->assertRedirect('/login');

    $response = $this->get(route('impersonation.status'));
    $response->assertRedirect('/login');
});
