<?php

namespace Tests\Feature\Livewire\Auth;

use App\Livewire\Auth\Login;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Session;
use Livewire\Livewire;
use Tests\TestCase;

class LoginTest extends TestCase
{
    public $user;
    protected function setUp(): void
    {
        parent::setUp();

        $this->user = User::factory()->create([
            'email' => 'test@example.com',
            'password' => bcrypt('password'),
        ]);
    }

    /** @test */
    public function it_renders_the_login_component(): void
    {
        $component = Livewire::test(Login::class);

        $component->assertStatus(200);
        $component->assertSee('Email');
        $component->assertSee('Password');
    }

    /** @test */
    public function it_validates_required_email_field(): void
    {
        $component = Livewire::test(Login::class);

        $component->set('email', '')
            ->call('login')
            ->assertHasErrors(['email' => 'required']);
    }

    /** @test */
    public function it_validates_email_format(): void
    {
        $component = Livewire::test(Login::class);

        $component->set('email', 'invalid-email')
            ->call('login')
            ->assertHasErrors(['email' => 'email']);
    }

    /** @test */
    public function it_validates_required_password_field(): void
    {
        $component = Livewire::test(Login::class);

        $component->set('password', '')
            ->call('login')
            ->assertHasErrors(['password' => 'required']);
    }

    /** @test */
    public function it_authenticates_user_with_valid_credentials(): void
    {
        $component = Livewire::test(Login::class);

        $component->set('email', 'test@example.com')
            ->set('password', 'password')
            ->call('login');

        $this->assertAuthenticatedAs($this->user);
        $component->assertRedirect('/dashboard');
    }

    /** @test */
    public function it_fails_authentication_with_invalid_credentials(): void
    {
        $component = Livewire::test(Login::class);

        $component->set('email', 'test@example.com')
            ->set('password', 'wrong-password')
            ->call('login')
            ->assertHasErrors('email');
    }

    /** @test */
    public function it_handles_rate_limiting(): void
    {
        // Clear any existing rate limit attempts
        RateLimiter::clear('login:'.request()->ip());

        // Exceed the rate limit (5 attempts by default)
        for ($i = 0; $i < 6; $i++) {
            $component = Livewire::test(Login::class);
            $component->set('email', 'test@example.com')
                ->set('password', 'wrong-password')
                ->call('login');
        }

        // Should be rate limited now
        $component = Livewire::test(Login::class);
        $component->set('email', 'test@example.com')
            ->set('password', 'password')
            ->call('login')
            ->assertHasErrors('email');
    }

    /** @test */
    public function it_redirects_authenticated_users_away(): void
    {
        $this->actingAs($this->user);

        $component = Livewire::test(Login::class);

        // Component should still render but show logged in state
        $component->assertStatus(200);
    }

    /** @test */
    public function it_handles_lockout_event(): void
    {
        // Clear any existing rate limit attempts
        RateLimiter::clear('login:'.request()->ip());

        // Exceed the rate limit to trigger lockout
        for ($i = 0; $i < 6; $i++) {
            $component = Livewire::test(Login::class);
            $component->set('email', 'test@example.com')
                ->set('password', 'wrong-password')
                ->call('login');
        }

        // Should be rate limited now
        $component = Livewire::test(Login::class);
        $component->set('email', 'test@example.com')
            ->set('password', 'password')
            ->call('login')
            ->assertHasErrors('email');
    }

    /** @test */
    public function it_clears_session_after_successful_login(): void
    {
        Session::put('old_url', '/some-page');

        $component = Livewire::test(Login::class);

        $component->set('email', 'test@example.com')
            ->set('password', 'password')
            ->call('login');

        $this->assertAuthenticatedAs($this->user);
        // User should be authenticated after successful login
        $this->assertTrue(Auth::check());
    }

    /** @test */
    public function it_remember_me_functionality_works(): void
    {
        $component = Livewire::test(Login::class);

        $component->set('email', 'test@example.com')
            ->set('password', 'password')
            ->set('remember', true)
            ->call('login');

        $this->assertAuthenticatedAs($this->user);
    }
}
