<?php

use App\Enums\RoleEnum;
use App\Filament\Pages\Auth\Registration;
use App\Models\User;
use App\Notifications\BroadcastNotification;
use Filament\Auth\Notifications\VerifyEmail;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
use Livewire\Livewire;
use Spatie\Permission\Models\Role;

uses(RefreshDatabase::class);

beforeEach(function () {
    Cache::flush();
    Role::firstOrCreate(['name' => RoleEnum::PERUSAHAAN->value, 'guard_name' => 'web']);
    Role::firstOrCreate(['name' => RoleEnum::ADMINISTRATOR->value, 'guard_name' => 'web']);
});

// 1. Page Access
describe('page access', function () {
    it('can render the registration page', function () {
        $this->get(route('filament.dashboard.auth.register'))
            ->assertSuccessful()
            ->assertSee('Nama Lengkap')
            ->assertSee('Alamat Surel')
            ->assertSee('Nama Pengguna')
            ->assertSee('Kata Sandi');
    });
});

// 2. Validation
describe('validation', function () {
    it('requires all fields', function () {
        Livewire::test(Registration::class)
            ->call('register')
            ->assertHasErrors([
                'data.name' => 'required',
                'data.email' => 'required',
                'data.username' => 'required',
                'data.password' => 'required',
            ]);
    });

    it('requires a unique email', function () {
        User::factory()->create(['email' => 'taken@example.com']);

        Livewire::test(Registration::class)
            ->fillForm([
                'name' => 'New User',
                'email' => 'taken@example.com',
                'username' => 'newuser',
                'password' => 'password',
            ])
            ->call('register')
            ->assertHasErrors(['data.email' => 'unique']);
    });

    it('requires a unique username', function () {
        User::factory()->create(['username' => 'takenuser']);

        Livewire::test(Registration::class)
            ->fillForm([
                'name' => 'New User',
                'email' => 'new@example.com',
                'username' => 'takenuser',
                'password' => 'password',
            ])
            ->call('register')
            ->assertHasErrors(['data.username' => 'unique']);
    });

    it('validates username length', function () {
        Livewire::test(Registration::class)
            ->fillForm(['username' => 'abc'])
            ->call('register')
            ->assertHasErrors(['data.username' => 'min']);

        Livewire::test(Registration::class)
            ->fillForm(['username' => 'alongusernamehere'])
            ->call('register')
            ->assertHasErrors(['data.username' => 'max']);
    });

    it('validates username format', function () {
        Livewire::test(Registration::class)
            ->fillForm(['username' => 'user name']) // spaces not allowed
            ->call('register')
            ->assertHasErrors(['data.username' => 'regex']);
    });
});

// 3. User Registration
describe('registration process', function () {
    it('can register a new user with correct data and and assigned role', function () {
        Notification::fake();

        Livewire::test(Registration::class)
            ->fillForm([
                'name' => 'John Doe',
                'email' => 'john.doe@example.com',
                'username' => 'johndoe',
                'password' => 'password',
            ])
            ->call('register')
            ->assertHasNoErrors()
            ->assertRedirect(route('filament.dashboard.pages.dashboard'));

        $this->assertDatabaseHas('users', [
            'email' => 'john.doe@example.com',
            'name' => 'John Doe',
            'username' => 'johndoe',
        ]);

        $user = User::where('email', 'john.doe@example.com')->first();

        expect($user)->not->toBeNull()
            ->and($user->hasRole(RoleEnum::PERUSAHAAN->value))->toBeTrue()
            ->and(Hash::check('password', $user->password))->toBeTrue();
    });
});

// 4. Authorization
describe('authorization', function () {
    it('redirects authenticated users from the registration page', function () {
        $user = User::factory()->create();

        $this->actingAs($user)
            ->get(route('filament.dashboard.auth.register'))
            ->assertRedirect(route('filament.dashboard.pages.dashboard'));
    });
});

// 5. Emails and Notifications
describe('notifications and emails', function () {
    it('dispatches email verification to the newly registered user', function () {
        Notification::fake();

        Livewire::test(Registration::class)
            ->fillForm([
                'name' => 'Bob Wilson',
                'email' => 'bob.wilson@example.com',
                'username' => 'bobwilson',
                'password' => 'password',
            ])
            ->call('register')
            ->assertHasNoErrors();

        $user = User::where('email', 'bob.wilson@example.com')->first();
        expect($user)->not->toBeNull();

        Notification::assertSentTo(
            $user,
            VerifyEmail::class
        );
    });

    it('sends broadcast notification to admins after user registration', function () {
        Notification::fake();

        // Create admin
        $admin = User::factory()->create(['email' => 'admin.test@example.com']);
        $admin->assignRole(RoleEnum::ADMINISTRATOR->value);

        Livewire::test(Registration::class)
            ->fillForm([
                'name' => 'Jane Smith',
                'email' => 'jane.smith@example.com',
                'username' => 'janesmith',
                'password' => 'password',
            ])
            ->call('register')
            ->assertHasNoErrors();

        Notification::assertSentTo(
            $admin,
            BroadcastNotification::class
        );
    });
});
