<?php

declare(strict_types=1);

use App\Support\Auth\Capabilities;
use App\Support\BackupHealth\TenantBackupHealthAssessment;
use App\Support\PortfolioTriage\PortfolioArrivalContextResolver;
use App\Support\PortfolioTriage\PortfolioArrivalContextToken;
use App\Support\RestoreSafety\RestoreResultAttention;
use App\Support\Tenants\TenantRecoveryTriagePresentation;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Request;
use Tests\Feature\Concerns\BuildsPortfolioTriageFixtures;

use function Pest\Laravel\mock;

uses(RefreshDatabase::class, BuildsPortfolioTriageFixtures::class);

function portfolioArrivalRequest(array $query, int $workspaceId): Request
{
    $request = Request::create('/admin/t/test-tenant', 'GET', $query);
    $session = app('session.store');
    $session->start();
    $session->put(WorkspaceContext::SESSION_KEY, $workspaceId);
    $request->setLaravelSession($session);

    return $request;
}

it('resolves a workspace-bound backup arrival context into the dashboard follow-up contract', function (): void {
    [$user, $tenant] = $this->makePortfolioTriageActor('Absent Backup ManagedEnvironment');
    $this->actingAs($user);

    $request = portfolioArrivalRequest([
        PortfolioArrivalContextToken::QUERY_PARAMETER => PortfolioArrivalContextToken::encode([
            'sourceSurface' => PortfolioArrivalContextToken::SOURCE_WORKSPACE_OVERVIEW,
            'tenantRouteKey' => (string) $tenant->external_id,
            'workspaceId' => (int) $tenant->workspace_id,
            'concernFamily' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH,
            'concernState' => TenantBackupHealthAssessment::POSTURE_ABSENT,
            'concernReason' => TenantBackupHealthAssessment::REASON_NO_BACKUP_BASIS,
        ]),
    ], (int) $tenant->workspace_id);

    $context = app(PortfolioArrivalContextResolver::class)->resolve($request, $tenant);

    expect($context)->not->toBeNull();
    expect($context->sourceSurface)->toBe(PortfolioArrivalContextToken::SOURCE_WORKSPACE_OVERVIEW)
        ->and($context->concernFamily)->toBe(PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH)
        ->and($context->concernState)->toBe(TenantBackupHealthAssessment::POSTURE_ABSENT)
        ->and($context->arrivalSummary)->toContain('workspace overview triage')
        ->and($context->nextStep['kind'])->toBe('backup_sets')
        ->and($context->nextStep['url'])->toContain('backup_health_reason='.TenantBackupHealthAssessment::REASON_NO_BACKUP_BASIS)
        ->and($context->returnTarget['kind'])->toBe('workspace_overview')
        ->and($context->currentTruthDelta)->toBe('Recovery evidence also still needs follow-up.');
});

it('returns null when the arrival token is bound to another tenant or workspace', function (): void {
    [$user, $tenant] = $this->makePortfolioTriageActor('Bound ManagedEnvironment');
    $this->actingAs($user);

    $wrongTenantRequest = portfolioArrivalRequest([
        PortfolioArrivalContextToken::QUERY_PARAMETER => PortfolioArrivalContextToken::encode([
            'sourceSurface' => PortfolioArrivalContextToken::SOURCE_WORKSPACE_OVERVIEW,
            'tenantRouteKey' => 'other-tenant',
            'workspaceId' => (int) $tenant->workspace_id,
            'concernFamily' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH,
            'concernState' => TenantBackupHealthAssessment::POSTURE_ABSENT,
            'concernReason' => TenantBackupHealthAssessment::REASON_NO_BACKUP_BASIS,
        ]),
    ], (int) $tenant->workspace_id);

    $wrongWorkspaceRequest = portfolioArrivalRequest([
        PortfolioArrivalContextToken::QUERY_PARAMETER => PortfolioArrivalContextToken::encode([
            'sourceSurface' => PortfolioArrivalContextToken::SOURCE_WORKSPACE_OVERVIEW,
            'tenantRouteKey' => (string) $tenant->external_id,
            'workspaceId' => 9999,
            'concernFamily' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH,
            'concernState' => TenantBackupHealthAssessment::POSTURE_ABSENT,
            'concernReason' => TenantBackupHealthAssessment::REASON_NO_BACKUP_BASIS,
        ]),
    ], (int) $tenant->workspace_id);

    expect(app(PortfolioArrivalContextResolver::class)->resolve($wrongTenantRequest, $tenant))->toBeNull()
        ->and(app(PortfolioArrivalContextResolver::class)->resolve($wrongWorkspaceRequest, $tenant))->toBeNull();
});

it('sanitizes tenant-registry return targets back to allowlisted filters only', function (): void {
    [$user, $tenant] = $this->makePortfolioTriageActor('Registry ManagedEnvironment');
    $this->actingAs($user);

    $request = portfolioArrivalRequest([
        PortfolioArrivalContextToken::QUERY_PARAMETER => PortfolioArrivalContextToken::encode([
            'sourceSurface' => PortfolioArrivalContextToken::SOURCE_TENANT_REGISTRY,
            'tenantRouteKey' => (string) $tenant->external_id,
            'workspaceId' => (int) $tenant->workspace_id,
            'concernFamily' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH,
            'concernState' => TenantBackupHealthAssessment::POSTURE_ABSENT,
            'concernReason' => TenantBackupHealthAssessment::REASON_NO_BACKUP_BASIS,
            'returnFilters' => [
                'backup_posture' => [
                    TenantBackupHealthAssessment::POSTURE_ABSENT,
                    'invalid',
                ],
                'recovery_evidence' => [
                    TenantRecoveryTriagePresentation::RECOVERY_EVIDENCE_UNVALIDATED,
                ],
                'triage_sort' => TenantRecoveryTriagePresentation::TRIAGE_SORT_WORST_FIRST,
                'leak' => ['managed_environment_id' => 999],
            ],
        ]),
    ], (int) $tenant->workspace_id);

    $context = app(PortfolioArrivalContextResolver::class)->resolve($request, $tenant);

    expect($context)->not->toBeNull();
    expect($context->returnTarget['kind'])->toBe('tenant_registry')
        ->and($context->returnTarget['url'])->toContain('backup_posture%5B0%5D=absent')
        ->and($context->returnTarget['url'])->toContain('recovery_evidence%5B0%5D=unvalidated')
        ->and($context->returnTarget['url'])->toContain('triage_sort=worst_first')
        ->and($context->returnTarget['url'])->not->toContain('leak');
});

it('degrades the next step truthfully when the operator cannot open deeper follow-up surfaces', function (): void {
    [$user, $tenant] = $this->makePortfolioTriageActor('Restricted ManagedEnvironment');
    $this->actingAs($user);

    mock(\App\Services\Auth\CapabilityResolver::class, function ($mock) use ($tenant): void {
        $mock->shouldReceive('can')
            ->andReturnUsing(static function ($user, $resolvedTenant, string $capability) use ($tenant): bool {
                expect((int) $resolvedTenant->getKey())->toBe((int) $tenant->getKey());

                return $capability !== Capabilities::TENANT_VIEW;
            });
    });

    $request = portfolioArrivalRequest([
        PortfolioArrivalContextToken::QUERY_PARAMETER => PortfolioArrivalContextToken::encode([
            'sourceSurface' => PortfolioArrivalContextToken::SOURCE_WORKSPACE_OVERVIEW,
            'tenantRouteKey' => (string) $tenant->external_id,
            'workspaceId' => (int) $tenant->workspace_id,
            'concernFamily' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH,
            'concernState' => TenantBackupHealthAssessment::POSTURE_ABSENT,
            'concernReason' => TenantBackupHealthAssessment::REASON_NO_BACKUP_BASIS,
        ]),
    ], (int) $tenant->workspace_id);

    $context = app(PortfolioArrivalContextResolver::class)->resolve($request, $tenant);

    expect($context)->not->toBeNull();
    expect($context->nextStep['disabled'])->toBeTrue()
        ->and($context->nextStep['url'])->toBeNull()
        ->and($context->nextStep['helperText'])->toBe(\App\Support\Rbac\UiTooltips::INSUFFICIENT_PERMISSION);
});

it('maps weakened recovery arrivals to restore-run detail and explains when current truth has changed', function (): void {
    [$user, $tenant] = $this->makePortfolioTriageActor('Recovery ManagedEnvironment');
    $this->actingAs($user);

    $backupSet = $this->seedPortfolioBackupConcern($tenant, TenantBackupHealthAssessment::POSTURE_HEALTHY);
    $restoreRun = $this->seedPortfolioRecoveryConcern(
        tenant: $tenant,
        reason: RestoreResultAttention::STATE_COMPLETED_WITH_FOLLOW_UP,
        backupSet: $backupSet,
    );

    $request = portfolioArrivalRequest([
        PortfolioArrivalContextToken::QUERY_PARAMETER => PortfolioArrivalContextToken::encode([
            'sourceSurface' => PortfolioArrivalContextToken::SOURCE_TENANT_REGISTRY,
            'tenantRouteKey' => (string) $tenant->external_id,
            'workspaceId' => (int) $tenant->workspace_id,
            'concernFamily' => PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE,
            'concernState' => TenantRecoveryTriagePresentation::RECOVERY_EVIDENCE_UNVALIDATED,
            'concernReason' => 'no_history',
            'returnFilters' => [
                'recovery_evidence' => [TenantRecoveryTriagePresentation::RECOVERY_EVIDENCE_UNVALIDATED],
                'triage_sort' => TenantRecoveryTriagePresentation::TRIAGE_SORT_WORST_FIRST,
            ],
        ]),
    ], (int) $tenant->workspace_id);

    $context = app(PortfolioArrivalContextResolver::class)->resolve($request, $tenant);

    expect($context)->not->toBeNull();
    expect($context->nextStep['kind'])->toBe('restore_run_detail')
        ->and($context->nextStep['url'])->toContain('/restore-runs/'.(string) $restoreRun->getKey())
        ->and($context->nextStep['url'])->toContain('recovery_posture_reason=completed_with_follow_up')
        ->and($context->currentTruthDelta)->toContain('Current recovery evidence now looks Weakened.');
});
