<?php

namespace Tests\Feature;

use App\Enums\UserRole;
use App\Filament\Pages\ProjectOverview;
use App\Filament\Resources\Users\Pages\ManageUsers;
use App\Models\User;
use Database\Seeders\DatabaseSeeder;
use Filament\Actions\Testing\TestAction;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Livewire\Livewire;
use Tests\TestCase;

class UserResourceTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();

        $this->withoutVite();
        $this->seed(DatabaseSeeder::class);
    }

    public function test_admin_can_access_user_resource(): void
    {
        $this->actingAs($this->user('ricardo.medeiros@katoennatie.com'))
            ->get(route('filament.admin.resources.users.index'))
            ->assertOk()
            ->assertSee('Usuários');
    }

    public function test_collaborator_cannot_access_user_resource(): void
    {
        $this->actingAs($this->user('david.gomes@katoennatie.com.br'))
            ->get(route('filament.admin.resources.users.index'))
            ->assertForbidden();
    }

    public function test_viewer_cannot_access_user_resource(): void
    {
        $this->actingAs($this->user('marcelo.martins@katoennatie.com'))
            ->get(route('filament.admin.resources.users.index'))
            ->assertForbidden();
    }

    public function test_inactive_user_cannot_access_the_panel(): void
    {
        $user = User::factory()->admin()->create(['is_active' => false]);

        $this->actingAs($user)
            ->get(ProjectOverview::getUrl())
            ->assertForbidden();
    }

    public function test_admin_can_create_and_edit_a_user(): void
    {
        $this->actingAs($this->user('ricardo.medeiros@katoennatie.com'));

        Livewire::test(ManageUsers::class)
            ->callAction(TestAction::make('create'), [
                'name' => 'Usuário de Teste',
                'email' => 'usuario.teste@example.com',
                'role' => UserRole::Collaborator->value,
                'is_active' => true,
                'password' => 'SenhaInicial#2026',
            ])
            ->assertHasNoActionErrors();

        $user = User::query()->where('email', 'usuario.teste@example.com')->sole();

        $this->assertTrue(Hash::check('SenhaInicial#2026', $user->password));

        Livewire::test(ManageUsers::class)
            ->callAction(TestAction::make('edit')->table($user), [
                'name' => 'Usuário Editado',
                'email' => 'usuario.editado@example.com',
                'role' => UserRole::Viewer->value,
                'is_active' => true,
                'password' => 'NovaSenha#2026',
            ])
            ->assertHasNoActionErrors();

        $user->refresh();

        $this->assertSame('Usuário Editado', $user->name);
        $this->assertSame('usuario.editado@example.com', $user->email);
        $this->assertSame(UserRole::Viewer, $user->role);
        $this->assertTrue(Hash::check('NovaSenha#2026', $user->password));
    }

    public function test_empty_password_does_not_replace_the_current_password_when_editing(): void
    {
        $this->actingAs($this->user('ricardo.medeiros@katoennatie.com'));
        $user = User::factory()->create([
            'password' => 'SenhaMantida#2026',
        ]);
        $originalPasswordHash = $user->getRawOriginal('password');

        Livewire::test(ManageUsers::class)
            ->callAction(TestAction::make('edit')->table($user), [
                'name' => 'Nome Atualizado',
                'email' => $user->email,
                'role' => $user->role->value,
                'is_active' => true,
                'password' => '',
            ])
            ->assertHasNoActionErrors();

        $user->refresh();

        $this->assertSame('Nome Atualizado', $user->name);
        $this->assertSame($originalPasswordHash, $user->getRawOriginal('password'));
        $this->assertTrue(Hash::check('SenhaMantida#2026', $user->password));
    }

    public function test_admin_cannot_deactivate_or_delete_own_user(): void
    {
        $admin = $this->user('ricardo.medeiros@katoennatie.com');

        $this->assertFalse($admin->can('deactivate', $admin));
        $this->assertFalse($admin->can('delete', $admin));
        $this->assertTrue($admin->isLastActiveAdmin());
    }

    private function user(string $email): User
    {
        return User::query()->where('email', $email)->sole();
    }
}
