<?php

declare(strict_types=1);

use App\Filament\Resources\TenantResource\Pages\ListTenants;
use App\Filament\Resources\TenantResource\Pages\ViewTenant;
use App\Models\AuditLog;
use App\Services\Auth\CapabilityResolver;
use App\Support\Auth\Capabilities;
use App\Models\Tenant;
use App\Models\TenantTriageReview;
use App\Support\Audit\AuditActionId;
use App\Support\BackupHealth\TenantBackupHealthAssessment;
use App\Support\PortfolioTriage\PortfolioArrivalContextToken;
use App\Support\Tenants\TenantRecoveryTriagePresentation;
use Carbon\CarbonImmutable;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Livewire\Livewire;
use App\Support\Workspaces\WorkspaceContext;
use Tests\Feature\Concerns\BuildsPortfolioTriageFixtures;

uses(BuildsPortfolioTriageFixtures::class);

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

it('renders review-state badges and all four review-state filters for the current backup slice', function (): void {
    CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 4, 10, 8, 0, 0, 'UTC'));

    [$user, $anchorTenant] = $this->makePortfolioTriageActor('Anchor Backup Tenant');

    $reviewedTenant = $this->makePortfolioTriagePeer($user, $anchorTenant, 'Reviewed Backup Tenant');
    $followUpTenant = $this->makePortfolioTriagePeer($user, $anchorTenant, 'Follow-up Backup Tenant');
    $changedTenant = $this->makePortfolioTriagePeer($user, $anchorTenant, 'Changed Backup Tenant');
    $notReviewedTenant = $this->makePortfolioTriagePeer($user, $anchorTenant, 'Not Reviewed Backup Tenant');
    $calmTenant = $this->makePortfolioTriagePeer($user, $anchorTenant, 'Calm Backup Tenant');

    foreach ([$reviewedTenant, $followUpTenant, $changedTenant, $notReviewedTenant] as $tenant) {
        $this->seedPortfolioBackupConcern($tenant, TenantBackupHealthAssessment::POSTURE_STALE);
    }

    $this->seedPortfolioBackupConcern($calmTenant, TenantBackupHealthAssessment::POSTURE_HEALTHY);

    $this->seedPortfolioTriageReview($reviewedTenant, PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH, TenantTriageReview::STATE_REVIEWED, $user);
    $this->seedPortfolioTriageReview($followUpTenant, PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH, TenantTriageReview::STATE_FOLLOW_UP_NEEDED, $user);
    $this->seedPortfolioTriageReview($changedTenant, PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH, TenantTriageReview::STATE_REVIEWED, $user, changedFingerprint: true);

    $this->portfolioTriageRegistryList($user, $anchorTenant, [
        'backup_posture' => [TenantBackupHealthAssessment::POSTURE_STALE],
    ])
        ->assertTableColumnExists('review_state')
        ->assertTableColumnFormattedStateSet('review_state', 'Reviewed', $reviewedTenant)
        ->assertTableColumnFormattedStateSet('review_state', 'Follow-up needed', $followUpTenant)
        ->assertTableColumnFormattedStateSet('review_state', 'Changed since review', $changedTenant)
        ->assertTableColumnFormattedStateSet('review_state', 'Not reviewed', $notReviewedTenant)
        ->assertDontSee('Calm Backup Tenant');

    $reviewedNames = $this->portfolioTriageRegistryList($user, $anchorTenant, [
        'backup_posture' => [TenantBackupHealthAssessment::POSTURE_STALE],
    ])
        ->filterTable('review_state', [TenantTriageReview::STATE_REVIEWED])
        ->instance()
        ->getFilteredTableQuery()
        ?->pluck('tenants.name')
        ->all();

    $followUpNames = $this->portfolioTriageRegistryList($user, $anchorTenant, [
        'backup_posture' => [TenantBackupHealthAssessment::POSTURE_STALE],
    ])
        ->filterTable('review_state', [TenantTriageReview::STATE_FOLLOW_UP_NEEDED])
        ->instance()
        ->getFilteredTableQuery()
        ?->pluck('tenants.name')
        ->all();

    $changedNames = $this->portfolioTriageRegistryList($user, $anchorTenant, [
        'backup_posture' => [TenantBackupHealthAssessment::POSTURE_STALE],
    ])
        ->filterTable('review_state', [TenantTriageReview::DERIVED_STATE_CHANGED_SINCE_REVIEW])
        ->instance()
        ->getFilteredTableQuery()
        ?->pluck('tenants.name')
        ->all();

    $notReviewedNames = $this->portfolioTriageRegistryList($user, $anchorTenant, [
        'backup_posture' => [TenantBackupHealthAssessment::POSTURE_STALE],
    ])
        ->filterTable('review_state', [TenantTriageReview::DERIVED_STATE_NOT_REVIEWED])
        ->instance()
        ->getFilteredTableQuery()
        ?->pluck('tenants.name')
        ->all();

    expect($reviewedNames)->toBe(['Reviewed Backup Tenant'])
        ->and($followUpNames)->toBe(['Follow-up Backup Tenant'])
        ->and($changedNames)->toBe(['Changed Backup Tenant'])
        ->and($notReviewedNames)->toBe(['Not Reviewed Backup Tenant']);
});

it('uses the highest-priority current concern family when the registry slice is mixed', function (): void {
    [$user, $anchorTenant] = $this->makePortfolioTriageActor('Anchor Mixed Tenant');
    $mixedTenant = $this->makePortfolioTriagePeer($user, $anchorTenant, 'Mixed Concern Tenant');

    $backupSet = $this->seedPortfolioBackupConcern($mixedTenant, TenantBackupHealthAssessment::POSTURE_STALE);
    $this->seedPortfolioRecoveryConcern($mixedTenant, 'failed', $backupSet);
    $this->seedPortfolioTriageReview(
        $mixedTenant,
        PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE,
        TenantTriageReview::STATE_FOLLOW_UP_NEEDED,
        $user,
    );

    $this->portfolioTriageRegistryList($user, $anchorTenant, [
        'triage_sort' => TenantRecoveryTriagePresentation::TRIAGE_SORT_WORST_FIRST,
    ])
        ->assertTableColumnFormattedStateSet('review_state', 'Follow-up needed', $mixedTenant)
        ->assertSee('Recovery evidence');
});

it('keeps review-state mutations in overflow with a preview-confirmed write path', function (): void {
    [$user, $anchorTenant] = $this->makePortfolioTriageActor('Anchor Action Tenant');
    $actionTenant = $this->makePortfolioTriagePeer($user, $anchorTenant, 'Action Backup Tenant');
    $this->seedPortfolioBackupConcern($actionTenant, TenantBackupHealthAssessment::POSTURE_STALE);

    $component = $this->portfolioTriageRegistryList($user, $anchorTenant, [
        'backup_posture' => [TenantBackupHealthAssessment::POSTURE_STALE],
    ])
        ->assertTableActionVisible('openTenant', $actionTenant)
        ->assertTableActionEnabled('markReviewed', $actionTenant)
        ->assertTableActionExists('markReviewed', fn (Action $action): bool => $action->isConfirmationRequired()
            && str_contains((string) $action->getModalDescription(), 'Concern family: Backup health')
            && str_contains((string) $action->getModalDescription(), 'Target state: Reviewed')
            && str_contains((string) $action->getModalDescription(), 'TenantPilot only'), $actionTenant)
        ->assertTableActionExists('markFollowUpNeeded', fn (Action $action): bool => $action->isConfirmationRequired(), $actionTenant);

    $action = $component->instance()->getAction([
        [
            'name' => 'markReviewed',
            'context' => [
                'table' => true,
                'recordKey' => (string) $actionTenant->getKey(),
            ],
        ],
    ]);

    expect(app(CapabilityResolver::class)->can($user, $actionTenant, Capabilities::TENANT_TRIAGE_REVIEW_MANAGE))->toBeTrue();

    expect($action)->not->toBeNull()
        ->and($action?->getRecord())->toBeInstanceOf(Tenant::class)
        ->and((int) $action?->getRecord()?->getKey())->toBe((int) $actionTenant->getKey())
        ->and($action?->isDisabled())->toBeFalse()
        ->and($component->instance()->mountedActionShouldOpenModal($action))->toBeTrue();

    $component->mountAction([
        [
            'name' => 'markReviewed',
            'context' => [
                'table' => true,
                'recordKey' => (string) $actionTenant->getKey(),
            ],
        ],
    ]);

    $mountedAction = $component->instance()->getMountedAction();

    expect($mountedAction)->not->toBeNull()
        ->and($mountedAction?->getRecord())->toBeInstanceOf(Tenant::class)
        ->and((int) $mountedAction?->getRecord()?->getKey())->toBe((int) $actionTenant->getKey());

    $component
        ->callMountedAction();

    expect(TenantTriageReview::query()
            ->where('tenant_id', (int) $actionTenant->getKey())
            ->where('concern_family', PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH)
            ->where('current_state', TenantTriageReview::STATE_REVIEWED)
            ->whereNull('resolved_at')
            ->exists())->toBeTrue()
        ->and(AuditLog::query()
            ->where('workspace_id', (int) $actionTenant->workspace_id)
            ->where('tenant_id', (int) $actionTenant->getKey())
            ->where('action', AuditActionId::TenantTriageReviewMarkedReviewed->value)
            ->exists())->toBeTrue()
        ->and($component->instance())->toBeInstanceOf(ListTenants::class);
});

it('keeps review-state mutations available on the tenant detail header for the current concern', function (): void {
    [$user, $anchorTenant] = $this->makePortfolioTriageActor('Anchor Detail Action Tenant');
    $actionTenant = $this->makePortfolioTriagePeer($user, $anchorTenant, 'Detail Action Backup Tenant');
    $this->seedPortfolioBackupConcern($actionTenant, TenantBackupHealthAssessment::POSTURE_STALE);

    $this->actingAs($user);
    Filament::setCurrentPanel('admin');
    Filament::setTenant(null, true);
    Filament::bootCurrentPanel();
    session([WorkspaceContext::SESSION_KEY => (int) $actionTenant->workspace_id]);

    $component = Livewire::actingAs($user)
        ->test(ViewTenant::class, ['record' => $actionTenant->getRouteKey()])
        ->assertActionVisible('markReviewed')
        ->assertActionEnabled('markReviewed')
        ->assertActionExists('markReviewed', fn (Action $action): bool => $action->isConfirmationRequired()
            && str_contains((string) $action->getModalDescription(), 'Concern family: Backup health')
            && str_contains((string) $action->getModalDescription(), 'Target state: Reviewed')
            && str_contains((string) $action->getModalDescription(), 'TenantPilot only'))
        ->assertActionVisible('markFollowUpNeeded')
        ->assertActionExists('markFollowUpNeeded', fn (Action $action): bool => $action->isConfirmationRequired()
            && str_contains((string) $action->getModalDescription(), 'Target state: Follow-up needed')
            && str_contains((string) $action->getModalDescription(), 'TenantPilot only'))
        ->mountAction('markReviewed')
        ->assertActionMounted('markReviewed')
        ->callMountedAction()
        ->assertHasNoActionErrors();

    expect(TenantTriageReview::query()
        ->where('tenant_id', (int) $actionTenant->getKey())
        ->where('concern_family', PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH)
        ->where('current_state', TenantTriageReview::STATE_REVIEWED)
        ->whereNull('resolved_at')
        ->exists())->toBeTrue()
        ->and(AuditLog::query()
            ->where('workspace_id', (int) $actionTenant->workspace_id)
            ->where('tenant_id', (int) $actionTenant->getKey())
            ->where('action', AuditActionId::TenantTriageReviewMarkedReviewed->value)
            ->exists())->toBeTrue()
        ->and($component->instance())->toBeInstanceOf(ViewTenant::class);
});
