<?php

declare(strict_types=1);

use App\Filament\System\Pages\Ops\Failures;
use App\Filament\System\Pages\Ops\Runbooks;
use App\Filament\System\Pages\Ops\Runs;
use App\Filament\System\Pages\Ops\Stuck;
use App\Filament\System\Pages\Ops\ViewRun;
use App\Models\AuditLog;
use App\Models\OperationRun;
use App\Models\PlatformUser;
use App\Models\ManagedEnvironment;
use App\Support\Auth\PlatformCapabilities;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\System\SystemOperationRunLinks;
use Carbon\CarbonImmutable;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Notifications\DatabaseNotification;
use Illuminate\Support\Facades\Notification as NotificationFacade;
use Livewire\Livewire;

uses(RefreshDatabase::class);

beforeEach(function () {
    Filament::setCurrentPanel('system');
    Filament::bootCurrentPanel();

    ManagedEnvironment::factory()->create([
        'managed_environment_id' => null,
        'external_id' => 'platform',
    ]);
});

afterEach(function () {
    CarbonImmutable::setTestNow();
});

it('keeps the operations list scan-first with one go to runbooks cta', function () {
    $run = OperationRun::factory()->create([
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
        'type' => 'inventory_sync',
    ]);

    $viewOnlyUser = PlatformUser::factory()->create([
        'capabilities' => [
            PlatformCapabilities::ACCESS_SYSTEM_PANEL,
            PlatformCapabilities::OPERATIONS_VIEW,
        ],
        'is_active' => true,
    ]);

    $this->actingAs($viewOnlyUser, 'platform');

    $livewire = Livewire::test(Runs::class)
        ->assertCanSeeTableRecords([$run])
        ->assertActionVisible('go_to_runbooks')
        ->assertActionExists('go_to_runbooks', fn (Action $action): bool => $action->getLabel() === 'Go to runbooks' && $action->getUrl() === Runbooks::getUrl(panel: 'system'));

    $table = $livewire->instance()->getTable();
    $emptyStateActions = collect($table->getEmptyStateActions())
        ->map(fn (Action $action): array => [
            'name' => $action->getName(),
            'label' => $action->getLabel(),
            'url' => $action->getUrl(),
        ])
        ->values()
        ->all();

    expect($livewire->instance()->getTitle())->toBe('Operations')
        ->and($table->getActions())->toBeEmpty()
        ->and($table->getBulkActions())->toBeEmpty()
        ->and($table->getRecordUrl($run))->toBe(SystemOperationRunLinks::view($run))
        ->and($emptyStateActions)->toBe([
            [
                'name' => 'go_to_runbooks_empty',
                'label' => 'Go to runbooks',
                'url' => Runbooks::getUrl(panel: 'system'),
            ],
        ]);
});

it('keeps the failed operations list scan-first with one show all operations cta', function () {
    $run = OperationRun::factory()->create([
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
        'type' => 'inventory_sync',
    ]);

    $viewOnlyUser = PlatformUser::factory()->create([
        'capabilities' => [
            PlatformCapabilities::ACCESS_SYSTEM_PANEL,
            PlatformCapabilities::OPERATIONS_VIEW,
        ],
        'is_active' => true,
    ]);

    $this->actingAs($viewOnlyUser, 'platform');

    $livewire = Livewire::test(Failures::class)
        ->assertCanSeeTableRecords([$run])
        ->assertActionVisible('show_all_operations')
        ->assertActionExists('show_all_operations', fn (Action $action): bool => $action->getLabel() === 'Show all operations' && $action->getUrl() === SystemOperationRunLinks::index());

    $table = $livewire->instance()->getTable();
    $emptyStateActions = collect($table->getEmptyStateActions())
        ->map(fn (Action $action): array => [
            'name' => $action->getName(),
            'label' => $action->getLabel(),
            'url' => $action->getUrl(),
        ])
        ->values()
        ->all();

    expect($livewire->instance()->getTitle())->toBe('Failed operations')
        ->and($table->getActions())->toBeEmpty()
        ->and($table->getBulkActions())->toBeEmpty()
        ->and($table->getRecordUrl($run))->toBe(SystemOperationRunLinks::view($run))
        ->and($emptyStateActions)->toBe([
            [
                'name' => 'show_all_operations_empty',
                'label' => 'Show all operations',
                'url' => SystemOperationRunLinks::index(),
            ],
        ]);
});

it('keeps the stuck operations list scan-first with one show all operations cta', function () {
    config()->set('tenantpilot.system_console.stuck_thresholds.queued_minutes', 10);
    config()->set('tenantpilot.system_console.stuck_thresholds.running_minutes', 20);

    CarbonImmutable::setTestNow(CarbonImmutable::parse('2026-02-27 10:00:00'));

    $run = OperationRun::factory()->create([
        'status' => OperationRunStatus::Queued->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'type' => 'inventory_sync',
        'created_at' => now()->subMinutes(30),
        'started_at' => null,
    ]);

    $viewOnlyUser = PlatformUser::factory()->create([
        'capabilities' => [
            PlatformCapabilities::ACCESS_SYSTEM_PANEL,
            PlatformCapabilities::OPERATIONS_VIEW,
        ],
        'is_active' => true,
    ]);

    $this->actingAs($viewOnlyUser, 'platform');

    $livewire = Livewire::test(Stuck::class)
        ->assertCanSeeTableRecords([$run])
        ->assertActionVisible('show_all_operations')
        ->assertActionExists('show_all_operations', fn (Action $action): bool => $action->getLabel() === 'Show all operations' && $action->getUrl() === SystemOperationRunLinks::index());

    $table = $livewire->instance()->getTable();
    $emptyStateActions = collect($table->getEmptyStateActions())
        ->map(fn (Action $action): array => [
            'name' => $action->getName(),
            'label' => $action->getLabel(),
            'url' => $action->getUrl(),
        ])
        ->values()
        ->all();

    expect($livewire->instance()->getTitle())->toBe('Stuck operations')
        ->and($table->getActions())->toBeEmpty()
        ->and($table->getBulkActions())->toBeEmpty()
        ->and($table->getRecordUrl($run))->toBe(SystemOperationRunLinks::view($run))
        ->and($emptyStateActions)->toBe([
            [
                'name' => 'show_all_operations_empty',
                'label' => 'Show all operations',
                'url' => SystemOperationRunLinks::index(),
            ],
        ]);
});

it('keeps detail-page triage, return paths, and audit behavior for manage operators', function () {
    NotificationFacade::fake();

    $failedRun = OperationRun::factory()->create([
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
        'type' => 'inventory_sync',
    ]);

    $runningRun = OperationRun::factory()->create([
        'status' => OperationRunStatus::Running->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'type' => 'inventory_sync',
        'created_at' => now()->subMinutes(15),
        'started_at' => now()->subMinutes(10),
    ]);

    $manageUser = PlatformUser::factory()->create([
        'capabilities' => [
            PlatformCapabilities::ACCESS_SYSTEM_PANEL,
            PlatformCapabilities::OPERATIONS_VIEW,
            PlatformCapabilities::OPERATIONS_MANAGE,
        ],
        'is_active' => true,
    ]);

    $this->actingAs($manageUser, 'platform');

    $failedRunView = Livewire::test(ViewRun::class, [
        'run' => $failedRun,
    ])
        ->assertActionVisible('show_all_operations')
        ->assertActionExists('show_all_operations', fn (Action $action): bool => $action->getLabel() === 'Show all operations' && $action->getUrl() === SystemOperationRunLinks::index())
        ->assertActionVisible('go_to_runbooks')
        ->assertActionExists('go_to_runbooks', fn (Action $action): bool => $action->getLabel() === 'Go to runbooks' && $action->getUrl() === Runbooks::getUrl(panel: 'system'))
        ->assertActionVisible('retry')
        ->assertActionExists('retry', fn (Action $action): bool => $action->getLabel() === 'Retry' && $action->isConfirmationRequired())
        ->assertActionHidden('cancel')
        ->assertActionVisible('mark_investigated')
        ->assertActionExists('mark_investigated', fn (Action $action): bool => $action->getLabel() === 'Mark investigated' && $action->isConfirmationRequired())
        ->mountAction('mark_investigated')
        ->assertActionMounted('mark_investigated')
        ->callMountedAction()
        ->assertHasActionErrors(['reason']);

    expect($failedRunView->instance()->getTitle())->toBe('Operation #'.(int) $failedRun->getKey());

    Livewire::test(ViewRun::class, [
        'run' => $failedRun,
    ])
        ->callAction('retry')
        ->assertHasNoActionErrors()
        ->assertNotified('Inventory sync queued');

    NotificationFacade::assertNothingSent();
    expect(DatabaseNotification::query()->count())->toBe(0);

    $retriedRun = OperationRun::query()
        ->whereKeyNot((int) $failedRun->getKey())
        ->latest('id')
        ->first();

    expect($retriedRun)->not->toBeNull();
    expect((string) $retriedRun?->status)->toBe(OperationRunStatus::Queued->value);
    expect((int) data_get($retriedRun?->context, 'triage.retry_of_run_id'))->toBe((int) $failedRun->getKey());

    $this->get(SystemOperationRunLinks::view($retriedRun))
        ->assertSuccessful()
        ->assertSee('Operation #'.(int) $retriedRun?->getKey())
        ->assertSee('Show all operations')
        ->assertSee('Go to runbooks');

    Livewire::test(ViewRun::class, [
        'run' => $failedRun,
    ])
        ->callAction('mark_investigated', data: [
            'reason' => 'Checked by platform operations',
        ])
        ->assertHasNoActionErrors()
        ->assertNotified('Run marked as investigated');

    Livewire::test(ViewRun::class, [
        'run' => $runningRun,
    ])
        ->assertActionVisible('show_all_operations')
        ->assertActionVisible('go_to_runbooks')
        ->assertActionHidden('retry')
        ->assertActionVisible('cancel')
        ->assertActionExists('cancel', fn (Action $action): bool => $action->getLabel() === 'Cancel' && $action->isConfirmationRequired())
        ->mountAction('cancel')
        ->assertActionMounted('cancel')
        ->callMountedAction()
        ->assertHasActionErrors(['reason']);

    Livewire::test(ViewRun::class, [
        'run' => $runningRun,
    ])
        ->assertActionVisible('cancel')
        ->assertActionVisible('mark_investigated')
        ->callAction('cancel', data: [
            'reason' => 'Stopping the in-flight run after operator triage.',
        ])
        ->assertHasNoActionErrors()
        ->assertNotified('Run cancelled');

    expect(AuditLog::query()->where('action', 'platform.system_console.retry')->exists())->toBeTrue();
    expect(AuditLog::query()->where('action', 'platform.system_console.cancel')->exists())->toBeTrue();
    expect(AuditLog::query()->where('action', 'platform.system_console.mark_investigated')->exists())->toBeTrue();

    $runningRun->refresh();

    expect((string) $runningRun->status)->toBe(OperationRunStatus::Completed->value)
        ->and((string) $runningRun->outcome)->toBe(OperationRunOutcome::Failed->value)
        ->and(data_get($runningRun->context, 'triage.cancel_reason'))->toBe('Stopping the in-flight run after operator triage.');
});

it('keeps detail inspection and navigation available while hiding triage for view-only operators', function () {
    $run = OperationRun::factory()->create([
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
        'type' => 'inventory_sync',
    ]);

    $viewOnlyUser = PlatformUser::factory()->create([
        'capabilities' => [
            PlatformCapabilities::ACCESS_SYSTEM_PANEL,
            PlatformCapabilities::OPERATIONS_VIEW,
        ],
        'is_active' => true,
    ]);

    $this->actingAs($viewOnlyUser, 'platform');

    Livewire::test(ViewRun::class, [
        'run' => $run,
    ])
        ->assertActionVisible('show_all_operations')
        ->assertActionExists('show_all_operations', fn (Action $action): bool => $action->getLabel() === 'Show all operations' && $action->getUrl() === SystemOperationRunLinks::index())
        ->assertActionVisible('go_to_runbooks')
        ->assertActionExists('go_to_runbooks', fn (Action $action): bool => $action->getLabel() === 'Go to runbooks' && $action->getUrl() === Runbooks::getUrl(panel: 'system'))
        ->assertActionHidden('retry')
        ->assertActionHidden('cancel')
        ->assertActionHidden('mark_investigated');

    $this->get(SystemOperationRunLinks::view($run))
        ->assertSuccessful()
        ->assertSee('Operation #'.(int) $run->getKey())
        ->assertSee('Show all operations')
        ->assertSee('Go to runbooks');
});
