<?php

use App\Enums\IsActive;
use App\Enums\RoleEnum;
use App\Filament\Resources\Master\SubClassifications\Pages\ManageSubClassifications;
use App\Models\Classification;
use App\Models\SubClassification;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

uses(RefreshDatabase::class);

beforeEach(function () {
    $this->user = User::factory()->create(['is_active' => IsActive::ACTIVE]);

    // Setup Permissions
    Permission::firstOrCreate(['name' => 'ViewAny:SubClassification', 'guard_name' => 'web']);
    Permission::firstOrCreate(['name' => 'Create:SubClassification', 'guard_name' => 'web']);
    Permission::firstOrCreate(['name' => 'Update:SubClassification', 'guard_name' => 'web']);
    Permission::firstOrCreate(['name' => 'Delete:SubClassification', 'guard_name' => 'web']);
    Permission::firstOrCreate(['name' => 'Restore:SubClassification', 'guard_name' => 'web']);
    Permission::firstOrCreate(['name' => 'ForceDelete:SubClassification', 'guard_name' => 'web']);

    $this->user->givePermissionTo([
        'ViewAny:SubClassification',
        'Create:SubClassification',
        'Update:SubClassification',
        'Delete:SubClassification',
        'Restore:SubClassification',
        'ForceDelete:SubClassification',
    ]);
});

test('can render subklasifikasi list page', function () {
    $this->actingAs($this->user);

    Livewire::test(ManageSubClassifications::class)
        ->assertSuccessful();
});

test('can list subklasifikasi', function () {
    $subClassifications = SubClassification::factory()->count(5)->create();

    $this->actingAs($this->user);

    Livewire::test(ManageSubClassifications::class)
        ->call('loadTable')
        ->assertCanSeeTableRecords($subClassifications);
});

test('can create subklasifikasi', function () {
    $classification = Classification::factory()->create(['is_active' => IsActive::ACTIVE]);

    $this->actingAs($this->user);

    Livewire::test(ManageSubClassifications::class)
        ->mountAction('create')
        ->setActionData([
            'classification_id' => $classification->id,
            'name' => 'Subklasifikasi Baru',
        ])
        ->callMountedAction()
        ->assertHasNoActionErrors();

    $this->assertDatabaseHas('sub_classifications', [
        'classification_id' => $classification->id,
        'name' => 'Subklasifikasi Baru',
    ]);
});

test('cannot create subklasifikasi with invalid data', function () {
    $this->actingAs($this->user);

    // Empty name
    Livewire::test(ManageSubClassifications::class)
        ->mountAction('create')
        ->setActionData(['name' => '', 'classification_id' => null])
        ->callMountedAction()
        ->assertHasActionErrors(['name' => 'required', 'classification_id' => 'required']);

    // Non-existent classification
    Livewire::test(ManageSubClassifications::class)
        ->mountAction('create')
        ->setActionData(['name' => 'Valid Name', 'classification_id' => 999999])
        ->callMountedAction()
        ->assertHasActionErrors(['classification_id']);
});

test('can edit subklasifikasi', function () {
    $subClassification = SubClassification::factory()->create();
    $newClassification = Classification::factory()->create(['is_active' => IsActive::ACTIVE]);

    $this->actingAs($this->user);

    Livewire::test(ManageSubClassifications::class)
        ->mountTableAction('edit', $subClassification)
        ->setActionData([
            'classification_id' => $newClassification->id,
            'name' => 'Subklasifikasi Updated',
        ])
        ->callMountedTableAction()
        ->assertHasNoActionErrors();

    expect($subClassification->refresh()->name)->toBe('Subklasifikasi Updated');
    expect($subClassification->classification_id)->toBe($newClassification->id);
});

test('can toggle is_active status', function () {
    $subClassification = SubClassification::factory()->create(['is_active' => IsActive::INACTIVE]);

    $this->actingAs($this->user);

    Livewire::test(ManageSubClassifications::class)
        ->call('updateTableColumnState', 'is_active', $subClassification->getKey(), true);

    expect($subClassification->refresh()->is_active)->toBe(IsActive::ACTIVE);
});

test('unauthorized user cannot render subklasifikasi page', function () {
    $unauthorizedUser = User::factory()->create(['is_active' => IsActive::ACTIVE]);

    $this->actingAs($unauthorizedUser);

    Livewire::test(ManageSubClassifications::class)
        ->assertForbidden();
});

test('user without update permission cannot see edit action', function () {
    $viewOnlyUser = User::factory()->create(['is_active' => IsActive::ACTIVE]);
    $viewOnlyUser->givePermissionTo('ViewAny:SubClassification');
    $subClassification = SubClassification::factory()->create();

    $this->actingAs($viewOnlyUser);

    Livewire::test(ManageSubClassifications::class)
        ->assertTableActionHidden('edit', $subClassification);
});

test('can delete subklasifikasi', function () {
    $subClassification = SubClassification::factory()->create();

    $this->actingAs($this->user);

    Livewire::test(ManageSubClassifications::class)
        ->callTableAction('delete', $subClassification);

    $this->assertSoftDeleted($subClassification);
});

test('can restore deleted subklasifikasi', function () {
    $roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
    $this->user->assignRole($roleDev);

    $subClassification = SubClassification::factory()->create(['deleted_at' => now()]);

    $this->actingAs($this->user);

    Livewire::test(ManageSubClassifications::class)
        ->filterTable('trashed', 'with')
        ->callTableAction('restore', $subClassification);

    $this->assertDatabaseHas('sub_classifications', [
        'id' => $subClassification->id,
        'deleted_at' => null,
    ]);
});

test('can force delete subklasifikasi', function () {
    $roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
    $this->user->assignRole($roleDev);

    $subClassification = SubClassification::factory()->create(['deleted_at' => now()]);

    $this->actingAs($this->user);

    Livewire::test(ManageSubClassifications::class)
        ->filterTable('trashed', 'only')
        ->callTableAction('forceDelete', $subClassification);

    $this->assertDatabaseMissing('sub_classifications', ['id' => $subClassification->id]);
});

test('trashed filter visibility depends on developer role', function () {
    $roleAdmin = Role::firstOrCreate(['name' => RoleEnum::ADMINISTRATOR->value, 'guard_name' => 'web']);
    $this->user->assignRole($roleAdmin);

    $this->actingAs($this->user);

    Livewire::test(ManageSubClassifications::class)
        ->assertTableFilterHidden('trashed');

    $roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
    $this->user->assignRole($roleDev);

    Livewire::test(ManageSubClassifications::class)
        ->assertTableFilterVisible('trashed');
});
