<?php

use App\Livewire\ConsentScreen;
use App\Models\Application;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

it('mounts correctly with session data', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create(['name' => 'Test Application']);
    
    $this->actingAs($user);
    
    // Set up session data
    session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback']);
    
    $component = Livewire::test(ConsentScreen::class);
    
    expect($component->get('client')->id)->toBe($app->id);
    expect($component->get('client')->name)->toBe('Test Application');
    expect($component->get('redirectUrl'))->toBe('https://example.com/callback');
});

it('displays client application name', function () {
    $user = User::factory()->create(['name' => 'John Doe']);
    $app = Application::factory()->create(['name' => 'My OAuth App']);
    
    $this->actingAs($user);
    
    session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback']);
    
    $component = Livewire::test(ConsentScreen::class);
    
    $component->assertSeeText('My OAuth App')
        ->assertSeeText('John Doe')
        ->assertSeeText('about to log into')
        ->assertSeeText('Logging in as:');
});

it('approves and redirects to redirect URL', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create();
    
    $this->actingAs($user);
    
    session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback?code=123']);
    
    Livewire::test(ConsentScreen::class)
        ->call('approve')
        ->assertRedirect('https://example.com/callback?code=123');
    
    // Check that session data is cleared
    expect(session('app_id'))->toBeNull();
    expect(session('redirect_on_confirm'))->toBeNull();
});

it('denies and redirects to dashboard', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create();
    
    $this->actingAs($user);
    
    session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback']);
    
    Livewire::test(ConsentScreen::class)
        ->call('deny')
        ->assertRedirect(route('dashboard'));
});

it('clears session data on approval', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create();
    
    $this->actingAs($user);
    
    session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback']);
    
    // Verify session data exists before approval
    expect(session('app_id'))->toBe($app->id);
    expect(session('redirect_on_confirm'))->toBe('https://example.com/callback');
    
    Livewire::test(ConsentScreen::class)
        ->call('approve');
    
    // Verify session data is cleared after approval
    expect(session('app_id'))->toBeNull();
    expect(session('redirect_on_confirm'))->toBeNull();
});

it('handles different redirect URL formats', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create();
    
    $this->actingAs($user);
    
    $redirectUrls = [
        'https://example.com/oauth/callback',
        'http://localhost:3000/auth/callback?state=xyz',
        'https://app.example.com:8080/callback?code=abc&state=def'
    ];
    
    foreach ($redirectUrls as $redirectUrl) {
        session(['app_id' => $app->id, 'redirect_on_confirm' => $redirectUrl]);
        
        Livewire::test(ConsentScreen::class)
            ->call('approve')
            ->assertRedirect($redirectUrl);
            
        // Reset session for next iteration
        session()->flush();
    }
});

it('can be rendered with valid session data', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create();
    
    $this->actingAs($user);
    
    session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback']);
    
    $component = Livewire::test(ConsentScreen::class);
    
    $component->assertStatus(200);
});

it('requires redirect URL in session', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create();
    
    $this->actingAs($user);
    
    // Set only app_id, missing redirect_on_confirm
    session(['app_id' => $app->id]);
    
    // This should fail because redirectUrl is typed as string and session('redirect_on_confirm') returns null
    expect(fn() => Livewire::test(ConsentScreen::class))
        ->toThrow(\Illuminate\View\ViewException::class);
});

it('displays confirm and cancel buttons', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create();
    
    $this->actingAs($user);
    
    session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback']);
    
    $component = Livewire::test(ConsentScreen::class);
    
    $component->assertSeeText('Confirm')
        ->assertSeeText('Cancel');
});

it('shows user name in consent message', function () {
    $user = User::factory()->create(['name' => 'Alice Smith']);
    $app = Application::factory()->create();
    
    $this->actingAs($user);
    
    session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback']);
    
    $component = Livewire::test(ConsentScreen::class);
    
    $component->assertSeeText('Alice Smith');
});

it('requires session data to mount', function () {
    $user = User::factory()->create();
    
    $this->actingAs($user);
    
    // No session data set - should fail due to strict typing
    expect(fn() => Livewire::test(ConsentScreen::class))
        ->toThrow(\Illuminate\View\ViewException::class);
});

it('handles application with special characters in name', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create(['name' => "O'Reilly's OAuth & API Service!"]);
    
    $this->actingAs($user);
    
    session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback']);
    
    $component = Livewire::test(ConsentScreen::class);
    
    $component->assertSeeText("O'Reilly's OAuth & API Service!");
});

it('preserves URL parameters in redirect URL', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create();
    
    $this->actingAs($user);
    
    $complexRedirectUrl = 'https://example.com/callback?code=xyz&state=abc123&scope=read%20write';
    session(['app_id' => $app->id, 'redirect_on_confirm' => $complexRedirectUrl]);
    
    Livewire::test(ConsentScreen::class)
        ->call('approve')
        ->assertRedirect($complexRedirectUrl);
});

it('does not redirect when denying without clearing app session data', function () {
    $user = User::factory()->create();
    $app = Application::factory()->create();
    
    $this->actingAs($user);
    
    session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback']);
    
    Livewire::test(ConsentScreen::class)
        ->call('deny')
        ->assertRedirect(route('dashboard'));
    
    // Note: deny() doesn't clear session data, only approve() does
    // This might be intentional behavior for security reasons
});

it('works with different user types', function () {
    $adminUser = User::factory()->create(['is_admin' => true, 'name' => 'Admin User']);
    $regularUser = User::factory()->create(['is_admin' => false, 'name' => 'Regular User']);
    $app = Application::factory()->create(['name' => 'Test App']);
    
    foreach ([$adminUser, $regularUser] as $user) {
        $this->actingAs($user);
        
        session(['app_id' => $app->id, 'redirect_on_confirm' => 'https://example.com/callback']);
        
        $component = Livewire::test(ConsentScreen::class);
        
        expect($component->get('client')->id)->toBe($app->id);
        $component->assertSeeText($user->name);
        
        // Clean up for next iteration
        auth()->logout();
        session()->flush();
    }
});