<?php

declare(strict_types=1);

use App\Filament\Pages\EnvironmentDashboard;
use App\Filament\Widgets\ManagedEnvironment\ManagedEnvironmentTriageArrivalContinuity;
use App\Models\AuditLog;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentTriageReview;
use App\Models\User;
use App\Support\Audit\AuditActionId;
use App\Support\BackupHealth\TenantBackupHealthAssessment;
use App\Support\PortfolioTriage\PortfolioArrivalContextToken;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Filament\Actions\Action;
use Livewire\Livewire;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Tests\Feature\Concerns\BuildsPortfolioTriageFixtures;

uses(BuildsPortfolioTriageFixtures::class);

function triageReviewArrivalState(ManagedEnvironment $tenant): array
{
    return [
        'sourceSurface' => PortfolioArrivalContextToken::SOURCE_TENANT_REGISTRY,
        'tenantRouteKey' => (string) $tenant->external_id,
        'workspaceId' => (int) $tenant->workspace_id,
        'concernFamily' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH,
        'concernState' => TenantBackupHealthAssessment::POSTURE_STALE,
        'concernReason' => TenantBackupHealthAssessment::REASON_LATEST_BACKUP_STALE,
        'returnFilters' => [
            'backup_posture' => [TenantBackupHealthAssessment::POSTURE_STALE],
        ],
    ];
}

function triageReviewDashboardWidget(User $user, ManagedEnvironment $tenant, array $state): mixed
{
    test()->actingAs($user);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
    setAdminPanelContext($tenant);
    request()->attributes->remove('portfolio_triage.arrival_context');

    return Livewire::withQueryParams([
        PortfolioArrivalContextToken::QUERY_PARAMETER => PortfolioArrivalContextToken::encode($state),
        'tenant' => (string) $tenant->slug,
    ])->actingAs($user)->test(ManagedEnvironmentTriageArrivalContinuity::class);
}

it('returns 404 for non-members on the tenant dashboard triage route', function (): void {
    $tenant = ManagedEnvironment::factory()->create(['status' => 'active']);
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');
    $this->seedPortfolioBackupConcern($tenant, TenantBackupHealthAssessment::POSTURE_STALE);

    $foreignTenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'workspace_id' => (int) $tenant->workspace_id,
    ]);
    $this->seedPortfolioBackupConcern($foreignTenant, TenantBackupHealthAssessment::POSTURE_STALE);

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get(EnvironmentDashboard::getUrl([
            PortfolioArrivalContextToken::QUERY_PARAMETER => PortfolioArrivalContextToken::encode(triageReviewArrivalState($foreignTenant)),
        ], panel: 'admin', tenant: $foreignTenant))
        ->assertNotFound();
});

it('shows review actions as disabled for readonly members and still rejects a bypassed mutation with 403', function (): void {
    $tenant = ManagedEnvironment::factory()->create(['status' => 'active']);
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly');
    $this->seedPortfolioBackupConcern($tenant, TenantBackupHealthAssessment::POSTURE_STALE);

    $component = triageReviewDashboardWidget($user, $tenant, triageReviewArrivalState($tenant))
        ->assertActionVisible('markReviewed')
        ->assertActionDisabled('markReviewed');

    $instance = $component->instance();
    $componentReflection = new ReflectionObject($instance);
    $cachedActionsProperty = $componentReflection->getProperty('cachedActions');
    $cachedActionsProperty->setAccessible(true);
    $cachedActions = $cachedActionsProperty->getValue($instance);
    $action = $cachedActions['markReviewed'] ?? null;

    expect($action)->not->toBeNull();

    $actionReflection = new ReflectionObject($action);
    $disabledProperty = $actionReflection->getProperty('isDisabled');
    $disabledProperty->setAccessible(true);
    $disabledProperty->setValue($action, false);
    $cachedActionsProperty->setValue($instance, $cachedActions);

    $instance->mountAction('markReviewed');

    $mountedAction = $instance->getMountedAction();
    expect($mountedAction)->not->toBeNull();

    $mountedReflection = new ReflectionObject($mountedAction);
    $mountedDisabledProperty = $mountedReflection->getProperty('isDisabled');
    $mountedDisabledProperty->setAccessible(true);
    $mountedDisabledProperty->setValue($mountedAction, false);

    try {
        $instance->callMountedAction();
        $this->fail('Expected a 403 when bypassing the disabled action.');
    } catch (HttpException $exception) {
        expect($exception->getStatusCode())->toBe(403);
    }

    expect(ManagedEnvironmentTriageReview::query()->count())->toBe(0);
});

it('writes review progress and audit state only after the preview-confirmed action executes', function (): void {
    [$user, $tenant] = $this->makePortfolioTriageActor('Authorization Success ManagedEnvironment', workspaceRole: 'owner');
    $this->seedPortfolioBackupConcern($tenant, TenantBackupHealthAssessment::POSTURE_STALE);

    $component = triageReviewDashboardWidget($user, $tenant, triageReviewArrivalState($tenant))
        ->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('markFollowUpNeeded');

    expect(ManagedEnvironmentTriageReview::query()->count())->toBe(0);

    $instance = $component->instance();

    setAdminPanelContext($tenant);

    $instance->callMountedAction();

    expect(ManagedEnvironmentTriageReview::query()
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->where('current_state', ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED)
        ->whereNull('resolved_at')
        ->exists())->toBeTrue()
        ->and(AuditLog::query()
            ->where('workspace_id', (int) $tenant->workspace_id)
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->where('action', AuditActionId::ManagedEnvironmentTriageReviewMarkedFollowUpNeeded->value)
            ->exists())->toBeTrue();

    Filament::setTenant(null, true);
});
