<?php

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

uses(RefreshDatabase::class);

it('can create a new application with valid data', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    Livewire::test(NewApplication::class)
        ->set('name', 'Test Application')
        ->set('redirect_uri', 'https://example.com/callback')
        ->call('create')
        ->assertRedirect(route('dashboard'));
    
    $app = Application::where('name', 'Test Application')->first();
    expect($app)->not()->toBeNull();
    expect($app->name)->toBe('Test Application');
    expect($app->redirect_uri)->toBe('https://example.com/callback');
    expect($app->client_id)->not()->toBeNull();
    expect($app->client_secret)->not()->toBeNull();
    expect(strlen($app->client_secret))->toBe(40);
});

it('generates unique client_id and client_secret', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    // Create first application
    Livewire::test(NewApplication::class)
        ->set('name', 'First App')
        ->set('redirect_uri', 'https://first.com/callback')
        ->call('create');
    
    // Create second application
    Livewire::test(NewApplication::class)
        ->set('name', 'Second App')
        ->set('redirect_uri', 'https://second.com/callback')
        ->call('create');
    
    $apps = Application::all();
    expect($apps->count())->toBe(2);
    
    $firstApp = $apps->first();
    $secondApp = $apps->last();
    
    expect($firstApp->client_id)->not()->toBe($secondApp->client_id);
    expect($firstApp->client_secret)->not()->toBe($secondApp->client_secret);
});

it('validates required name field', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    Livewire::test(NewApplication::class)
        ->set('name', '')
        ->set('redirect_uri', 'https://example.com/callback')
        ->call('create')
        ->assertHasErrors(['name' => 'required']);
    
    expect(Application::count())->toBe(0);
});

it('validates required redirect_uri field', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    Livewire::test(NewApplication::class)
        ->set('name', 'Test App')
        ->set('redirect_uri', '')
        ->call('create')
        ->assertHasErrors(['redirect_uri' => 'required']);
    
    expect(Application::count())->toBe(0);
});

it('validates redirect_uri must be a valid URL', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    Livewire::test(NewApplication::class)
        ->set('name', 'Test App')
        ->set('redirect_uri', 'not-a-valid-url')
        ->call('create')
        ->assertHasErrors(['redirect_uri' => 'url']);
    
    expect(Application::count())->toBe(0);
});

it('accepts various valid URL formats for redirect_uri', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    $validUrls = [
        'https://example.com/callback',
        'http://localhost:3000/auth',
        'https://subdomain.example.com/oauth/callback',
        'https://app.example.com:8080/auth/callback'
    ];
    
    foreach ($validUrls as $index => $url) {
        Livewire::test(NewApplication::class)
            ->set('name', "Test App {$index}")
            ->set('redirect_uri', $url)
            ->call('create')
            ->assertHasNoErrors();
    }
    
    expect(Application::count())->toBe(count($validUrls));
});

it('resets form fields after successful creation', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    $component = Livewire::test(NewApplication::class)
        ->set('name', 'Test Application')
        ->set('redirect_uri', 'https://example.com/callback')
        ->call('create');
    
    expect($component->get('name'))->toBe('');
    expect($component->get('redirect_uri'))->toBe('');
});

it('prevents non-admin users from creating applications', function () {
    $user = User::factory()->create(['is_admin' => false]);
    
    $this->actingAs($user);
    
    // Test the policy directly first
    expect($user->can('create', Application::class))->toBe(false);
    
    // Test that Livewire component correctly handles authorization
    $response = $this->withoutExceptionHandling();
    
    $this->expectException(\Illuminate\Auth\Access\AuthorizationException::class);
    
    Livewire::test(NewApplication::class)
        ->set('name', 'Test Application')
        ->set('redirect_uri', 'https://example.com/callback')
        ->call('create');
});

it('can be rendered by admin users', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    $component = Livewire::test(NewApplication::class);
    
    $component->assertStatus(200);
    expect($component->get('name'))->toBe('');
    expect($component->get('redirect_uri'))->toBe('');
});

it('handles special characters in app name', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    $specialName = "My App's & Company's OAuth-2 Service!";
    
    Livewire::test(NewApplication::class)
        ->set('name', $specialName)
        ->set('redirect_uri', 'https://example.com/callback')
        ->call('create')
        ->assertRedirect(route('dashboard'));
    
    $app = Application::where('name', $specialName)->first();
    expect($app)->not()->toBeNull();
    expect($app->name)->toBe($specialName);
});

it('validates multiple validation errors at once', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    Livewire::test(NewApplication::class)
        ->set('name', '')
        ->set('redirect_uri', 'invalid-url')
        ->call('create')
        ->assertHasErrors(['name' => 'required', 'redirect_uri' => 'url']);
    
    expect(Application::count())->toBe(0);
});

it('generates UUID format for client_id', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    Livewire::test(NewApplication::class)
        ->set('name', 'Test Application')
        ->set('redirect_uri', 'https://example.com/callback')
        ->call('create');
    
    $app = Application::first();
    
    // Check UUID format (8-4-4-4-12 characters)
    expect($app->client_id)->toMatch('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/');
});

it('generates random string for client_secret with correct length', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    Livewire::test(NewApplication::class)
        ->set('name', 'Test Application')
        ->set('redirect_uri', 'https://example.com/callback')
        ->call('create');
    
    $app = Application::first();
    
    expect(strlen($app->client_secret))->toBe(40);
    expect($app->client_secret)->toMatch('/^[A-Za-z0-9]+$/');
});

it('creates application with all required fields populated', function () {
    $admin = User::factory()->create(['is_admin' => true]);
    
    $this->actingAs($admin);
    
    Livewire::test(NewApplication::class)
        ->set('name', 'Complete Test App')
        ->set('redirect_uri', 'https://complete.example.com/callback')
        ->call('create');
    
    $app = Application::first();
    
    expect($app->name)->toBe('Complete Test App');
    expect($app->redirect_uri)->toBe('https://complete.example.com/callback');
    expect($app->client_id)->not()->toBeNull();
    expect($app->client_secret)->not()->toBeNull();
    expect($app->icon)->toBeNull(); // icon is not set by this form
    expect($app->created_at)->not()->toBeNull();
    expect($app->updated_at)->not()->toBeNull();
});