<?php

namespace Tests\Feature\Auth;

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

class LoginTest extends TestCase
{
    use RefreshDatabase;

    public function test_successful_login_with_valid_credentials()
    {
        $user = User::factory()->create([
            'email' => 'valid@example.com',
            'password' => bcrypt('password'),
            'email_verified_at' => now(),
        ]);

        $response = $this->post(route('login.store'), [
            'login' => 'valid@example.com',
            'password' => 'password',
        ]);

        $this->assertAuthenticated();
        // User without specific role (null/default) redirects to packages for package selection
        $response->assertRedirect('/packages');
        $this->assertEquals('valid@example.com', Auth::user()->email);
    }

    public function test_successful_login_with_username()
    {
        $user = User::factory()->create([
            'username' => 'validuser',
            'password' => bcrypt('password'),
            'email_verified_at' => now(),
        ]);

        $response = $this->post(route('login.store'), [
            'login' => 'validuser',
            'password' => 'password',
        ]);

        $this->assertAuthenticated();
        // User without specific role (null/default) redirects to packages for package selection
        $response->assertRedirect('/packages');
        $this->assertEquals('validuser', Auth::user()->username);
    }

    public function test_login_fails_with_invalid_credentials()
    {
        User::factory()->create([
            'email' => 'invalid@example.com',
            'password' => bcrypt('password'),
        ]);

        $response = $this->post(route('login.store'), [
            'login' => 'invalid@example.com',
            'password' => 'wrongpassword',
        ]);

        $this->assertGuest();
        $response->assertStatus(302);
        $response->assertRedirect(route('login', absolute: false));
        $response->assertSessionHasErrors(['login' => 'Diese Anmeldedaten wurden nicht gefunden.']);
        $response->assertSessionHas('error', 'Diese Anmeldedaten wurden nicht gefunden.');
    }

    public function test_login_success_shows_success_flash()
    {
        $user = User::factory()->create([
            'email' => 'success@example.com',
            'role' => 'user', // Regular user
            'password' => bcrypt('password'),
            'email_verified_at' => now(),
        ]);

        $response = $this->post(route('login.store'), [
            'login' => 'success@example.com',
            'password' => 'password',
        ]);

        $this->assertAuthenticated();
        // Regular users now redirect to /packages for package selection
        $response->assertRedirect('/packages');
        $response->assertSessionHas('success', 'Sie sind nun eingeloggt.');
    }

    public function test_login_honors_return_to_parameter()
    {
        $user = User::factory()->create([
            'email' => 'return@example.com',
            'role' => 'user', // Regular user
            'password' => bcrypt('password'),
            'email_verified_at' => now(),
        ]);

        // Test that return_to parameter is honored - set it to a specific dashboard path
        $target = '/marketing/profile';
        $encoded = rtrim(strtr(base64_encode($target), '+/', '-_'), '=');

        $response = $this->post(route('login.store'), [
            'login' => 'return@example.com',
            'password' => 'password',
            'return_to' => $encoded,
        ]);

        $this->assertAuthenticated();
        $response->assertRedirect($target);
    }

    public function test_login_prefers_intended_url_over_return_to_parameter()
    {
        $user = User::factory()->create([
            'email' => 'tenant@example.com',
            'role' => 'tenant_admin',
            'password' => bcrypt('password'),
            'email_verified_at' => now(),
        ]);

        $intended = url('/event-admin/dashboard?from=intended-test');
        $returnTarget = '/event-admin/dashboard';
        $encodedReturn = rtrim(strtr(base64_encode($returnTarget), '+/', '-_'), '=');

        $response = $this
            ->withSession(['url.intended' => $intended])
            ->post(route('login.store'), [
                'login' => 'tenant@example.com',
                'password' => 'password',
                'return_to' => $encodedReturn,
            ]);

        $this->assertAuthenticated();
        $this->assertSame($user->id, Auth::id());
        $response->assertRedirect($intended);
    }

    public function test_tenant_admin_login_with_absolute_intended_redirects_to_event_admin_dashboard(): void
    {
        $user = User::factory()->create([
            'email' => 'absolute@example.com',
            'role' => 'tenant_admin',
            'password' => bcrypt('password'),
            'email_verified_at' => now(),
        ]);

        $intended = url('/event-admin/dashboard?from=oauth');

        $response = $this
            ->withSession(['url.intended' => $intended])
            ->post(route('login.store'), [
                'login' => 'absolute@example.com',
                'password' => 'password',
            ]);

        $this->assertAuthenticatedAs($user);
        $response->assertRedirect($intended);

        $dashboardResponse = $this->get('/dashboard');
        $dashboardResponse->assertRedirect('/event-admin/dashboard?from=oauth');
    }

    public function test_tenant_admin_login_ignores_non_admin_return_path()
    {
        $user = User::factory()->create([
            'email' => 'admin@example.com',
            'role' => 'tenant_admin',
            'password' => bcrypt('password'),
            'email_verified_at' => now(),
        ]);

        $encodedReturn = rtrim(strtr(base64_encode('/dashboard'), '+/', '-_'), '=');

        $response = $this->post(route('login.store'), [
            'login' => 'admin@example.com',
            'password' => 'password',
            'return_to' => $encodedReturn,
        ]);

        $this->assertAuthenticatedAs($user);
        $response->assertRedirect('/event-admin/dashboard');
    }

    public function test_tenant_admin_can_access_login_with_admin_return_path_when_authenticated()
    {
        $user = User::factory()->create([
            'email' => 'already@logged.in',
            'role' => 'tenant_admin',
            'password' => bcrypt('password'),
            'email_verified_at' => now(),
        ]);

        $this->actingAs($user);

        $adminStart = '/event-admin/start?return_to='.rtrim(strtr(base64_encode('/event-admin/dashboard'), '+/', '-_'), '=');
        $encoded = rtrim(strtr(base64_encode($adminStart), '+/', '-_'), '=');

        $response = $this->get('/de/login?return_to='.$encoded);
        $response->assertRedirect('/dashboard');

        $eventAdminResponse = $this->get('/event-admin/dashboard');
        $eventAdminResponse->assertOk();
    }

    public function test_login_redirects_unverified_user_to_verification_notice()
    {
        $user = User::factory()->create([
            'email' => 'unverified@example.com',
            'password' => bcrypt('password'),
            'email_verified_at' => null,
        ]);

        $response = $this->post(route('login.store'), [
            'login' => 'unverified@example.com',
            'password' => 'password',
        ]);

        $this->assertAuthenticated();
        $response->assertRedirect(route('verification.notice', absolute: false));
    }

    public function test_login_redirects_unverified_user_to_verification_link_when_intended(): void
    {
        $user = User::factory()->create([
            'email' => 'verify@example.com',
            'password' => bcrypt('password'),
            'email_verified_at' => null,
        ]);

        $verificationUrl = URL::temporarySignedRoute(
            'verification.verify',
            now()->addMinutes(60),
            ['id' => $user->id, 'hash' => sha1($user->email)],
            absolute: false,
        );

        $response = $this->withSession(['url.intended' => $verificationUrl])->post(route('login.store'), [
            'login' => 'verify@example.com',
            'password' => 'password',
        ]);

        $this->assertAuthenticated();
        $response->assertRedirect($verificationUrl);
    }

    public function test_rate_limiting_on_failed_logins()
    {
        $user = User::factory()->create([
            'email' => 'ratelimit@example.com',
            'password' => bcrypt('password'),
        ]);

        // Simulate 5 failed attempts
        for ($i = 0; $i < 5; $i++) {
            $response = $this->post(route('login.store'), [
                'login' => 'ratelimit@example.com',
                'password' => 'wrongpassword',
            ]);
            $response->assertStatus(302);
            $response->assertSessionHasErrors(['login' => 'Diese Anmeldedaten wurden nicht gefunden.']);
        }

        $response = $this->post(route('login.store'), [
            'login' => 'ratelimit@example.com',
            'password' => 'wrongpassword',
        ]);

        $this->assertGuest();
        $response->assertStatus(302);
        $response->assertSessionHasErrors(['login']);
        $this->assertStringContainsString(
            'Zu viele Login-Versuche.',
            collect(session('errors')->get('login'))->first()
        );
    }
}
