<?php

namespace Tests\Feature;

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

class LoginNotificationTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        RateLimiter::clear('login-attempts:test@example.com');
    }

    /**
     * Test Case 1 & 7: Invalid email/password and validation cases
     */
    public function test_invalid_email_or_password_displays_inline_error(): void
    {
        // 1. Incorrect password
        $user = User::create([
            'msnv'        => 5001,
            'name'        => 'Test User',
            'mail'        => 'test@example.com',
            'pass'        => md5('password123'),
            'departments' => config('constants.DEPARTMENTS')[0],
            'role'        => config('constants.ROLE_MEMBER'),
            'status'      => config('constants.STATUS_ACTIVE'),
            'card'        => 10,
            'flag_send'   => config('constants.FLAG_SEND_ENABLED'),
            'first_login' => config('constants.FIRST_LOGIN_FALSE'),
        ]);

        $response = $this->post('/login', [
            'mail'     => 'test@example.com',
            'password' => 'wrong_password',
        ]);

        $response->assertRedirect();
        $response->assertSessionHasErrors(['mail' => 'Thông tin đăng nhập không đúng. Vui lòng nhập lại']);

        // 2. Empty fields
        $response2 = $this->post('/login', [
            'mail'     => '',
            'password' => '',
        ]);
        $response2->assertRedirect();
        $response2->assertSessionHasErrors(['mail' => 'Thông tin đăng nhập không đúng. Vui lòng nhập lại']);

        // 3. Invalid email format
        $response3 = $this->post('/login', [
            'mail'     => 'invalid-email-format',
            'password' => 'password123',
        ]);
        $response3->assertRedirect();
        $response3->assertSessionHasErrors(['mail' => 'Thông tin đăng nhập không đúng. Vui lòng nhập lại']);

        // 4. Email too long
        $response4 = $this->post('/login', [
            'mail'     => str_repeat('a', 256) . '@example.com',
            'password' => 'password123',
        ]);
        $response4->assertRedirect();
        $response4->assertSessionHasErrors(['mail' => 'Thông tin đăng nhập không đúng. Vui lòng nhập lại']);

        // 5. Password too long
        $response5 = $this->post('/login', [
            'mail'     => 'test@example.com',
            'password' => str_repeat('p', 101),
        ]);
        $response5->assertRedirect();
        $response5->assertSessionHasErrors(['mail' => 'Thông tin đăng nhập không đúng. Vui lòng nhập lại']);
    }

    /**
     * Test Case 2: Account disabled / no access permission
     */
    public function test_inactive_user_displays_permission_error_dialog(): void
    {
        $user = User::create([
            'msnv'        => 5002,
            'name'        => 'Inactive User',
            'mail'        => 'test@example.com',
            'pass'        => md5('password123'),
            'departments' => config('constants.DEPARTMENTS')[0],
            'role'        => config('constants.ROLE_MEMBER'),
            'status'      => config('constants.STATUS_INACTIVE'), // 0
            'card'        => 10,
            'flag_send'   => config('constants.FLAG_SEND_ENABLED'),
            'first_login' => config('constants.FIRST_LOGIN_FALSE'),
        ]);

        $response = $this->post('/login', [
            'mail'     => 'test@example.com',
            'password' => 'password123',
        ]);

        $response->assertRedirect();
        $response->assertSessionHas('dialog_error_permission', 'Bạn không có quyền truy cập. Vui lòng liên hệ quản trị viên');
        $this->assertFalse(\Illuminate\Support\Facades\Auth::check());
    }

    /**
     * Test Case 3: Session expired
     */
    public function test_session_expired_redirects_with_session_expired_flash(): void
    {
        $response = $this->get('/my-page'); // Requires auth

        $response->assertRedirect(route('login'));
        $response->assertSessionHas('session_expired', true);
    }

    /**
     * Test Case 4: Login success
     */
    public function test_login_success_redirects_correctly(): void
    {
        // 1. Member redirect to My Page
        $member = User::create([
            'msnv'        => 5003,
            'name'        => 'Member User',
            'mail'        => 'member@example.com',
            'pass'        => md5('password123'),
            'departments' => config('constants.DEPARTMENTS')[0],
            'role'        => config('constants.ROLE_MEMBER'),
            'status'      => config('constants.STATUS_ACTIVE'),
            'card'        => 10,
            'flag_send'   => config('constants.FLAG_SEND_ENABLED'),
            'first_login' => config('constants.FIRST_LOGIN_FALSE'),
        ]);

        $response = $this->post('/login', [
            'mail'     => 'member@example.com',
            'password' => 'password123',
        ]);

        $response->assertRedirect(route('user.dashboard'));
        $this->assertTrue(\Illuminate\Support\Facades\Auth::check());
        $this->assertEquals($member->id, \Illuminate\Support\Facades\Auth::user()->id);

        \Illuminate\Support\Facades\Auth::logout();

        // 2. Admin redirect to Admin User List
        $admin = User::create([
            'msnv'        => 5004,
            'name'        => 'Admin User',
            'mail'        => 'admin@example.com',
            'pass'        => md5('password123'),
            'departments' => config('constants.DEPARTMENTS')[0],
            'role'        => config('constants.ROLE_ADMIN'),
            'status'      => config('constants.STATUS_ACTIVE'),
            'card'        => 10,
            'flag_send'   => config('constants.FLAG_SEND_ENABLED'),
            'first_login' => config('constants.FIRST_LOGIN_FALSE'),
        ]);

        $response2 = $this->post('/login', [
            'mail'     => 'admin@example.com',
            'password' => 'password123',
        ]);

        $response2->assertRedirect(route('admin.dashboard'));
        $this->assertTrue(\Illuminate\Support\Facades\Auth::check());
    }

    /**
     * Test Case 5: First login
     */
    public function test_first_login_redirects_to_login_page_with_first_login_dialog(): void
    {
        $user = User::create([
            'msnv'        => 5005,
            'name'        => 'First Login User',
            'mail'        => 'first@example.com',
            'pass'        => md5('password123'),
            'departments' => config('constants.DEPARTMENTS')[0],
            'role'        => config('constants.ROLE_MEMBER'),
            'status'      => config('constants.STATUS_ACTIVE'),
            'card'        => 10,
            'flag_send'   => config('constants.FLAG_SEND_ENABLED'),
            'first_login' => config('constants.FIRST_LOGIN_TRUE'),
        ]);

        $response = $this->post('/login', [
            'mail'     => 'first@example.com',
            'password' => 'password123',
        ]);

        $response->assertRedirect(route('login'));
        $response->assertSessionHas('dialog_first_login', true);
        $this->assertTrue(\Illuminate\Support\Facades\Auth::check());
    }

    public function test_admin_first_login_does_not_redirect_to_change_password(): void
    {
        $admin = User::create([
            'msnv'        => 5007,
            'name'        => 'First Login Admin',
            'mail'        => 'first_admin@example.com',
            'pass'        => md5('password123'),
            'departments' => config('constants.DEPARTMENTS')[0],
            'role'        => config('constants.ROLE_ADMIN'),
            'status'      => config('constants.STATUS_ACTIVE'),
            'card'        => 10,
            'flag_send'   => config('constants.FLAG_SEND_ENABLED'),
            'first_login' => config('constants.FIRST_LOGIN_TRUE'),
        ]);

        $response = $this->post('/login', [
            'mail'     => 'first_admin@example.com',
            'password' => 'password123',
        ]);

        $response->assertRedirect(route('admin.dashboard'));
        $response->assertSessionMissing('dialog_first_login');
        $this->assertTrue(\Illuminate\Support\Facades\Auth::check());
    }

    /**
     * Test Case 6: Brute-force protection
     */
    public function test_brute_force_protection_locks_after_5_failed_attempts(): void
    {
        $user = User::create([
            'msnv'        => 5006,
            'name'        => 'Lockout User',
            'mail'        => 'test@example.com',
            'pass'        => md5('password123'),
            'departments' => config('constants.DEPARTMENTS')[0],
            'role'        => config('constants.ROLE_MEMBER'),
            'status'      => config('constants.STATUS_ACTIVE'),
            'card'        => 10,
            'flag_send'   => config('constants.FLAG_SEND_ENABLED'),
            'first_login' => config('constants.FIRST_LOGIN_FALSE'),
        ]);

        // First 5 attempts fail
        for ($i = 0; $i < 5; $i++) {
            $response = $this->post('/login', [
                'mail'     => 'test@example.com',
                'password' => 'wrong_password',
            ]);
            $response->assertSessionHasErrors(['mail' => 'Thông tin đăng nhập không đúng. Vui lòng nhập lại']);
        }

        // 6th attempt is blocked by brute force protection
        $response6 = $this->post('/login', [
            'mail'     => 'test@example.com',
            'password' => 'wrong_password',
        ]);

        $response6->assertSessionHas('dialog_error_brute_force', 'Tài khoản của bạn tạm thời bị khóa do nhập sai mật khẩu quá 5 lần. Vui lòng thử lại sau 15 phút.');

        // 7th attempt with CORRECT password is also blocked
        $response7 = $this->post('/login', [
            'mail'     => 'test@example.com',
            'password' => 'password123',
        ]);

        $response7->assertSessionHas('dialog_error_brute_force', 'Tài khoản của bạn tạm thời bị khóa do nhập sai mật khẩu quá 5 lần. Vui lòng thử lại sau 15 phút.');
        $this->assertFalse(\Illuminate\Support\Facades\Auth::check());
    }
}
