<?php

declare(strict_types=1);

use App\Filament\Resources\BackupScheduleResource;
use App\Filament\Resources\BackupScheduleResource\Pages\ListBackupSchedules;
use App\Filament\Resources\BackupSetResource;
use App\Filament\Resources\BackupSetResource\Pages\ListBackupSets;
use App\Filament\Resources\PolicyResource\Pages\ListPolicies;
use App\Filament\Resources\RestoreRunResource;
use App\Filament\Resources\RestoreRunResource\Pages\ListRestoreRuns;
use App\Filament\Resources\Workspaces\Pages\ListWorkspaces;
use App\Filament\Resources\Workspaces\WorkspaceResource;
use App\Jobs\SyncPoliciesJob;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Filament\Tables\Table;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\App;
use Livewire\Features\SupportTesting\Testable;
use Livewire\Livewire;

uses(RefreshDatabase::class);

function getFeature122EmptyStateTable(Testable $component): Table
{
    return $component->instance()->getTable();
}

function getFeature122EmptyStateAction(Testable $component, string $name): ?Action
{
    foreach (getFeature122EmptyStateTable($component)->getEmptyStateActions() as $action) {
        if ($action instanceof Action && $action->getName() === $name) {
            return $action;
        }
    }

    return null;
}

function makeWorkspaceListComponent(string $role = 'owner'): Testable
{
    $workspace = Workspace::factory()->create([
        'archived_at' => now(),
    ]);

    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'user_id' => (int) $user->getKey(),
        'role' => $role,
    ]);

    $user->forceFill([
        'last_workspace_id' => (int) $workspace->getKey(),
    ])->save();

    test()->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()]);

    return Livewire::test(ListWorkspaces::class);
}

it('defines the policies empty state contract and keeps the sync CTA outcome intact', function (): void {
    App::setLocale('en');

    Queue::fake();
    bindFailHardGraphClient();

    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user);
    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    $component = Livewire::test(ListPolicies::class)
        ->assertTableEmptyStateActionsExistInOrder(['sync'])
        ->assertSee(__('localization.policy.resource.empty_state_heading'))
        ->assertSee(__('localization.policy.resource.empty_state_description'));

    $table = getFeature122EmptyStateTable($component);

    expect($table->getEmptyStateHeading())->toBe(__('localization.policy.resource.empty_state_heading'));
    expect($table->getEmptyStateDescription())->toBe(__('localization.policy.resource.empty_state_description'));
    expect($table->getEmptyStateIcon())->toBe('heroicon-o-arrow-path');

    $action = getFeature122EmptyStateAction($component, 'sync');

    expect($action)->not->toBeNull();
    expect($action?->getLabel())->toBe(__('localization.policy.resource.sync_action_primary'));

    $component
        ->mountAction('sync')
        ->callMountedAction()
        ->assertHasNoActionErrors();

    Queue::assertPushed(SyncPoliciesJob::class);
});

it('defines the backup sets empty state contract and links its CTA to create', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user);
    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    $component = Livewire::test(ListBackupSets::class)
        ->assertTableEmptyStateActionsExistInOrder(['create'])
        ->assertSee('No backup sets')
        ->assertSee('Create a backup set to start protecting your configurations.');

    $table = getFeature122EmptyStateTable($component);

    expect($table->getEmptyStateHeading())->toBe('No backup sets');
    expect($table->getEmptyStateDescription())->toBe('Create a backup set to start protecting your configurations.');
    expect($table->getEmptyStateIcon())->toBe('heroicon-o-archive-box');

    $action = getFeature122EmptyStateAction($component, 'create');

    expect($action)->not->toBeNull();
    expect($action?->getLabel())->toBe('Create backup set');
    expect($action?->getUrl())->toBe(BackupSetResource::getUrl('create', tenant: $tenant));
});

it('defines the restore runs empty state contract and links its CTA to create', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user);
    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    $component = Livewire::test(ListRestoreRuns::class)
        ->assertTableEmptyStateActionsExistInOrder(['create'])
        ->assertSee('No restore runs')
        ->assertSee('Start a restoration from a backup set.');

    $table = getFeature122EmptyStateTable($component);

    expect($table->getEmptyStateHeading())->toBe('No restore runs');
    expect($table->getEmptyStateDescription())->toBe('Start a restoration from a backup set.');
    expect($table->getEmptyStateIcon())->toBe('heroicon-o-arrow-path-rounded-square');

    $action = getFeature122EmptyStateAction($component, 'create');

    expect($action)->not->toBeNull();
    expect($action?->getLabel())->toBe('New restore run');
    expect($action?->getUrl())->toBe(RestoreRunResource::getUrl('create', tenant: $tenant));
});

it('defines the backup schedules empty state contract and links its CTA to create', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user);
    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    $component = Livewire::test(ListBackupSchedules::class)
        ->assertTableEmptyStateActionsExistInOrder(['create'])
        ->assertSee('No schedules configured')
        ->assertSee('Set up automated backups.');

    $table = getFeature122EmptyStateTable($component);

    expect($table->getEmptyStateHeading())->toBe('No schedules configured');
    expect($table->getEmptyStateDescription())->toBe('Set up automated backups.');
    expect($table->getEmptyStateIcon())->toBe('heroicon-o-clock');

    $action = getFeature122EmptyStateAction($component, 'create');

    expect($action)->not->toBeNull();
    expect($action?->getLabel())->toBe('New backup schedule');
    expect($action?->getUrl())->toBe(BackupScheduleResource::getUrl('create', tenant: $tenant));
});

it('defines the workspaces empty state contract and links its CTA to create', function (): void {
    $component = makeWorkspaceListComponent()
        ->assertTableEmptyStateActionsExistInOrder(['create'])
        ->assertSee('No workspaces')
        ->assertSee('Create your first workspace.');

    $table = getFeature122EmptyStateTable($component);

    expect($table->getEmptyStateHeading())->toBe('No workspaces');
    expect($table->getEmptyStateDescription())->toBe('Create your first workspace.');
    expect($table->getEmptyStateIcon())->toBe('heroicon-o-squares-2x2');

    $action = getFeature122EmptyStateAction($component, 'create');

    expect($action)->not->toBeNull();
    expect($action?->getLabel())->toBe('New workspace');
    expect($action?->getUrl())->toBe(WorkspaceResource::getUrl('create'));
});
