<?php

declare(strict_types=1);

use App\Support\BackupHealth\TenantBackupHealthAssessment;
use App\Support\PortfolioTriage\PortfolioArrivalContextToken;
use App\Support\RestoreSafety\RestoreResultAttention;
use App\Support\Tenants\TenantRecoveryTriagePresentation;

it('encodes and decodes bounded portfolio arrival token state deterministically', function (): void {
    $state = [
        'sourceSurface' => PortfolioArrivalContextToken::SOURCE_TENANT_REGISTRY,
        'tenantRouteKey' => 'tenant-abc',
        'workspaceId' => 12,
        'concernFamily' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH,
        'concernState' => TenantBackupHealthAssessment::POSTURE_STALE,
        'concernReason' => TenantBackupHealthAssessment::REASON_LATEST_BACKUP_STALE,
        'returnFilters' => [
            'backup_posture' => [
                TenantBackupHealthAssessment::POSTURE_STALE,
                TenantBackupHealthAssessment::POSTURE_DEGRADED,
            ],
            'triage_sort' => TenantRecoveryTriagePresentation::TRIAGE_SORT_WORST_FIRST,
        ],
    ];

    $token = PortfolioArrivalContextToken::encode($state);

    expect($token)->toBeString()
        ->and($token)->not->toContain('+')
        ->and($token)->not->toContain('/')
        ->and($token)->not->toContain('=')
        ->and(PortfolioArrivalContextToken::decode($token))->toBe($state);
});

it('returns null for malformed or unsupported portfolio arrival tokens', function (): void {
    expect(PortfolioArrivalContextToken::decode(''))->toBeNull()
        ->and(PortfolioArrivalContextToken::decode('not-base64url'))->toBeNull();

    $payload = json_encode([
        'v' => 999,
        'sourceSurface' => PortfolioArrivalContextToken::SOURCE_WORKSPACE_OVERVIEW,
        'tenantRouteKey' => 'tenant-abc',
        'concernFamily' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH,
        'concernState' => TenantBackupHealthAssessment::POSTURE_ABSENT,
    ], JSON_THROW_ON_ERROR);

    $token = rtrim(strtr(base64_encode($payload), '+/', '-_'), '=');

    expect(PortfolioArrivalContextToken::decode($token))->toBeNull();
});

it('rejects unsupported family state and reason combinations', function (): void {
    $unknownFamilyPayload = json_encode([
        'v' => 1,
        'sourceSurface' => PortfolioArrivalContextToken::SOURCE_WORKSPACE_OVERVIEW,
        'tenantRouteKey' => 'tenant-abc',
        'concernFamily' => 'unknown_family',
        'concernState' => TenantBackupHealthAssessment::POSTURE_ABSENT,
    ], JSON_THROW_ON_ERROR);

    $unknownStatePayload = json_encode([
        'v' => 1,
        'sourceSurface' => PortfolioArrivalContextToken::SOURCE_WORKSPACE_OVERVIEW,
        'tenantRouteKey' => 'tenant-abc',
        'concernFamily' => PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE,
        'concernState' => TenantBackupHealthAssessment::POSTURE_STALE,
    ], JSON_THROW_ON_ERROR);

    $unknownReasonPayload = json_encode([
        'v' => 1,
        'sourceSurface' => PortfolioArrivalContextToken::SOURCE_TENANT_REGISTRY,
        'tenantRouteKey' => 'tenant-abc',
        'concernFamily' => PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE,
        'concernState' => TenantRecoveryTriagePresentation::RECOVERY_EVIDENCE_WEAKENED,
        'concernReason' => TenantBackupHealthAssessment::REASON_LATEST_BACKUP_STALE,
    ], JSON_THROW_ON_ERROR);

    expect(PortfolioArrivalContextToken::decode(rtrim(strtr(base64_encode($unknownFamilyPayload), '+/', '-_'), '=')))->toBeNull()
        ->and(PortfolioArrivalContextToken::decode(rtrim(strtr(base64_encode($unknownStatePayload), '+/', '-_'), '=')))->toBeNull()
        ->and(PortfolioArrivalContextToken::decode(rtrim(strtr(base64_encode($unknownReasonPayload), '+/', '-_'), '=')))->toBeNull();
});

it('drops unsupported tenant-registry return filters while keeping allowlisted ones', function (): void {
    $state = [
        'sourceSurface' => PortfolioArrivalContextToken::SOURCE_TENANT_REGISTRY,
        'tenantRouteKey' => 'tenant-abc',
        'workspaceId' => 12,
        'concernFamily' => PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE,
        'concernState' => TenantRecoveryTriagePresentation::RECOVERY_EVIDENCE_WEAKENED,
        'concernReason' => RestoreResultAttention::STATE_FAILED,
        'returnFilters' => [
            'backup_posture' => [TenantBackupHealthAssessment::POSTURE_ABSENT],
            'triage_sort' => TenantRecoveryTriagePresentation::TRIAGE_SORT_WORST_FIRST,
            'ignore_me' => ['leak'],
            'nested' => ['bad' => ['value']],
        ],
    ];

    $decoded = PortfolioArrivalContextToken::decode(
        PortfolioArrivalContextToken::encode($state),
    );

    expect($decoded)->toMatchArray([
        'sourceSurface' => PortfolioArrivalContextToken::SOURCE_TENANT_REGISTRY,
        'concernFamily' => PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE,
        'concernState' => TenantRecoveryTriagePresentation::RECOVERY_EVIDENCE_WEAKENED,
        'concernReason' => RestoreResultAttention::STATE_FAILED,
        'returnFilters' => [
            'backup_posture' => [TenantBackupHealthAssessment::POSTURE_ABSENT],
            'triage_sort' => TenantRecoveryTriagePresentation::TRIAGE_SORT_WORST_FIRST,
        ],
    ]);
});
