<?php

use App\Models\BackupItem;
use App\Models\BackupSet;
use App\Models\BaselineProfile;
use App\Models\BaselineSnapshot;
use App\Models\BaselineTenantAssignment;
use App\Models\EnvironmentReview;
use App\Models\EvidenceSnapshot;
use App\Models\Finding;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentOnboardingSession;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\ProviderCredential;
use App\Models\RestoreRun;
use App\Models\StoredReport;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Services\Auth\CapabilityResolver;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Services\EnvironmentReviews\EnvironmentReviewService;
use App\Services\Evidence\EvidenceSnapshotService;
use App\Services\Graph\GraphClientInterface;
use App\Services\Tenants\TenantActionPolicySurface;
use App\Support\Evidence\EvidenceCompletenessState;
use App\Support\Evidence\EvidenceSnapshotStatus;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
use App\Support\Providers\ProviderConnectionType;
use App\Support\Providers\ProviderConsentStatus;
use App\Support\Providers\ProviderCredentialKind;
use App\Support\Providers\ProviderCredentialSource;
use App\Support\Providers\ProviderVerificationStatus;
use App\Support\Tenants\TenantActionDescriptor;
use App\Support\Tenants\TenantActionSurface;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Pest\PendingCalls\TestCall;
use Tests\Feature\Findings\Concerns\InteractsWithFindingsWorkflow;
use Tests\Support\AssertsNoOutboundHttp;
use Tests\Support\FailHardGraphClient;

/*
|--------------------------------------------------------------------------
| Test Case
|--------------------------------------------------------------------------
|
| The closure you provide to your test functions is always bound to a specific PHPUnit test
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
| need to change it using the "pest()" function to bind a different classes or traits.
|
*/

pest()->extend(Tests\TestCase::class)
    ->use(RefreshDatabase::class)
    ->in('Feature');

pest()->use(InteractsWithFindingsWorkflow::class)
    ->in('Feature/Findings', 'Feature/Audit');

pest()->extend(Tests\TestCase::class)
    ->use(RefreshDatabase::class)
    ->in('Browser');

pest()->extend(Tests\TestCase::class)
    ->in('Unit');

pest()->extend(Tests\TestCase::class)
    ->in('Architecture');

pest()->extend(Tests\TestCase::class)
    ->in('Deprecation');

pest()->group('browser')
    ->in('Browser');

pest()->group('ui-light')
    ->in(
        'Feature/Filament/BackupSetAdminTenantParityTest.php',
    );

pest()->group('ui-workflow')
    ->in(
        'Feature/Baselines/BaselineCompareMatrixCompareAllActionTest.php',
        'Feature/Baselines/BaselineCompareMatrixBuilderTest.php',
        'Feature/Drift/DriftBulkAcknowledgeAllMatchingConfirmationTest.php',
        'Feature/Findings/FindingExceptionRenewalTest.php',
        'Feature/Findings/FindingsListFiltersTest.php',
        'Feature/Findings/FindingWorkflowRowActionsTest.php',
        'Feature/Findings/FindingWorkflowViewActionsTest.php',
        'Feature/Filament/BaselineActionAuthorizationTest.php',
        'Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php',
        'Feature/Filament/BaselineProfileCompareStartSurfaceTest.php',
        'Feature/Findings/FindingBulkActionsTest.php',
        'Feature/SettingsFoundation/WorkspaceSettingsManageTest.php',
        'Feature/Rbac/OnboardingWizardUiEnforcementTest.php',
    );

pest()->group('surface-guard')
    ->in(
        'Feature/OpsUx',
        'Feature/Filament/Alerts/AlertsKpiHeaderTest.php',
        'Feature/Filament/PanelNavigationSegregationTest.php',
        'Feature/Filament/EnvironmentReviewHeaderDisciplineTest.php',
        'Feature/Filament/WorkspaceOnlySurfaceTenantIndependenceTest.php',
        'Feature/Guards/ActionSurfaceContractTest.php',
        'Feature/Guards/OperationLifecycleOpsUxGuardTest.php',
        'Feature/ProviderConnections/CredentialLeakGuardTest.php',
        'Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php',
        'Feature/Rbac/WorkspaceMembershipsRelationManagerUiEnforcementTest.php',
    );

pest()->group('discovery-heavy')
    ->in(
        'Feature/Filament/PolicyResourceAdminSearchParityTest.php',
        'Feature/Filament/PolicyVersionAdminSearchParityTest.php',
    );

beforeEach(function () {
    putenv('INTUNE_TENANT_ID');
    unset($_ENV['INTUNE_TENANT_ID'], $_SERVER['INTUNE_TENANT_ID']);

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

afterEach(function (): void {
    Filament::setTenant(null, true);
    Filament::setCurrentPanel(null);
});

/*
|--------------------------------------------------------------------------
| Expectations
|--------------------------------------------------------------------------
|
| When you're writing tests, you often need to check that values meet certain conditions. The
| "expect()" function gives you access to a set of "expectations" methods that you can use
| to assert different things. Of course, you may extend the Expectation API at any time.
|
*/

expect()->extend('toBeOne', function () {
    return $this->toBe(1);
});

function fakeIdToken(string $tenantId): string
{
    $header = rtrim(strtr(base64_encode(json_encode(['alg' => 'HS256', 'typ' => 'JWT'])), '+/', '-_'), '=');
    $payload = rtrim(strtr(base64_encode(json_encode(['tid' => $tenantId])), '+/', '-_'), '=');

    return $header.'.'.$payload.'.signature';
}

/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
|
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
| project that you don't want to repeat in every file. Here you can also expose helpers as
| global functions to help you to reduce the number of lines of code in your test files.
|
*/

function something()
{
    // ..
}

/**
 * @return array{0: Workspace, 1: User}
 */
function localizationWorkspaceMember(string $role = 'manager'): array
{
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'user_id' => (int) $user->getKey(),
        'role' => $role,
    ]);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

    return [$workspace, $user];
}

function repo_root(): string
{
    $configuredRoot = env('TENANTATLAS_REPO_ROOT');

    if (is_string($configuredRoot) && $configuredRoot !== '') {
        if (str_starts_with($configuredRoot, DIRECTORY_SEPARATOR)) {
            return rtrim($configuredRoot, DIRECTORY_SEPARATOR);
        }

        $resolvedConfiguredRoot = realpath(base_path($configuredRoot));

        if ($resolvedConfiguredRoot !== false) {
            return $resolvedConfiguredRoot;
        }
    }

    $resolvedDefaultRoot = realpath(base_path('../..'));

    if ($resolvedDefaultRoot !== false) {
        return $resolvedDefaultRoot;
    }

    return dirname(base_path(), 2);
}

function repo_path(string $path = ''): string
{
    $root = repo_root();

    if ($path === '') {
        return $root;
    }

    return $root.DIRECTORY_SEPARATOR.ltrim($path, DIRECTORY_SEPARATOR);
}

/**
 * @param  array<string, mixed>  $payload
 * @param  array<string, mixed>  $overrides
 * @return array<string, mixed>
 */
function mutateTrustedStatePayload(array $payload, array $overrides): array
{
    return array_replace_recursive($payload, $overrides);
}

/**
 * @param  array<string, mixed>  $data
 * @param  list<string>  $errorKeys
 */
function assertScopedSelectorRejected(mixed $component, string $action, array $data, array $errorKeys = ['managed_environment_id']): mixed
{
    return $component
        ->callAction($action, data: $data)
        ->assertHasActionErrors($errorKeys);
}

/**
 * Spec test naming helper.
 *
 * Convention for focused runs:
 * - Prefix every Spec 081 test title with "Spec081 ".
 * - Keep filenames suffixed with "Spec081Test.php".
 * - Command: `vendor/bin/sail artisan test --compact --filter=Spec081`
 */
function spec081(string $description): string
{
    $normalized = trim($description);

    if ($normalized === '') {
        return 'Spec081';
    }

    return str_starts_with($normalized, 'Spec081 ')
        ? $normalized
        : 'Spec081 '.$normalized;
}

/**
 * Convenience wrapper for Spec 081 tests.
 */
function itSpec081(string $description, ?\Closure $closure = null): TestCall
{
    $call = it(spec081($description), $closure);
    $call->group('spec081');

    return $call;
}

function bindFailHardGraphClient(): void
{
    app()->instance(GraphClientInterface::class, new FailHardGraphClient);
}

function assertNoOutboundHttp(\Closure $callback): mixed
{
    return AssertsNoOutboundHttp::run($callback);
}

/**
 * @param  array<string, mixed>  $attributes
 */
function createInventorySyncOperationRun(ManagedEnvironment $tenant, array $attributes = []): \App\Models\OperationRun
{
    $context = is_array($attributes['context'] ?? null) ? $attributes['context'] : [];

    if (array_key_exists('selection_hash', $attributes)) {
        if (is_string($attributes['selection_hash']) && $attributes['selection_hash'] !== '') {
            $context['selection_hash'] = $attributes['selection_hash'];
        }

        unset($attributes['selection_hash']);
    }

    if (array_key_exists('selection_payload', $attributes)) {
        if (is_array($attributes['selection_payload'])) {
            $context = array_merge($context, $attributes['selection_payload']);
        }

        unset($attributes['selection_payload']);
    }

    if (! isset($context['selection_hash']) || ! is_string($context['selection_hash']) || $context['selection_hash'] === '') {
        $context['selection_hash'] = hash('sha256', 'inventory-sync-selection-default');
    }

    if (! isset($context['policy_types']) || ! is_array($context['policy_types'])) {
        $context['policy_types'] = ['deviceConfiguration'];
    }

    if (! isset($context['categories']) || ! is_array($context['categories'])) {
        $context['categories'] = [];
    }

    if (! array_key_exists('include_foundations', $context)) {
        $context['include_foundations'] = false;
    }

    if (! array_key_exists('include_dependencies', $context)) {
        $context['include_dependencies'] = false;
    }

    $finishedAt = $attributes['finished_at'] ?? null;
    unset($attributes['finished_at']);

    $providedStatus = (string) ($attributes['status'] ?? 'success');
    $normalizedStatus = match ($providedStatus) {
        'pending', 'queued' => 'queued',
        'running' => 'running',
        'completed' => 'completed',
        default => 'completed',
    };

    $normalizedOutcome = match ($providedStatus) {
        'success' => 'succeeded',
        'partial' => 'partially_succeeded',
        'skipped' => 'blocked',
        'failed' => 'failed',
        'pending', 'queued', 'running' => 'pending',
        default => $normalizedStatus === 'completed' ? 'succeeded' : 'pending',
    };

    $attributes['type'] = (string) ($attributes['type'] ?? 'inventory_sync');
    $attributes['workspace_id'] = (int) ($attributes['workspace_id'] ?? $tenant->workspace_id);
    $attributes['status'] = in_array($providedStatus, ['queued', 'running', 'completed'], true)
        ? $providedStatus
        : $normalizedStatus;
    $attributes['outcome'] = (string) ($attributes['outcome'] ?? $normalizedOutcome);
    $attributes['context'] = array_merge($context, is_array($attributes['context'] ?? null) ? $attributes['context'] : []);

    if ($finishedAt !== null && ! array_key_exists('completed_at', $attributes)) {
        $attributes['completed_at'] = $finishedAt;
    }

    return \App\Models\OperationRun::factory()
        ->for($tenant)
        ->create($attributes);
}

/**
 * Create a completed inventory sync run with coverage proof in context.
 *
 * @param  array<string, string>  $statusByType  Example: ['deviceConfiguration' => 'succeeded']
 * @param  list<string>  $foundationTypes
 * @param  array<string, mixed>  $attributes
 */
function createInventorySyncOperationRunWithCoverage(
    ManagedEnvironment $tenant,
    array $statusByType,
    array $foundationTypes = [],
    array $attributes = [],
): \App\Models\OperationRun {
    $context = is_array($attributes['context'] ?? null) ? $attributes['context'] : [];
    $inventory = is_array($context['inventory'] ?? null) ? $context['inventory'] : [];

    $inventory['coverage'] = \App\Support\Inventory\InventoryCoverage::buildPayload(
        statusByType: $statusByType,
        foundationTypes: $foundationTypes,
    );

    $context['inventory'] = $inventory;
    $attributes['context'] = $context;

    if (! array_key_exists('finished_at', $attributes) && ! array_key_exists('completed_at', $attributes)) {
        $attributes['finished_at'] = now();
    }

    $attributes['type'] ??= \App\Support\OperationRunType::InventorySync->value;
    $attributes['status'] ??= \App\Support\OperationRunStatus::Completed->value;
    $attributes['outcome'] ??= \App\Support\OperationRunOutcome::Succeeded->value;

    return createInventorySyncOperationRun($tenant, $attributes);
}

/**
 * @return array<string, array{workspace: bool, membership: bool, session: bool, provider: bool, credential: bool, cache: bool, uiContext: bool}>
 */
function createUserWithTenantProfileCatalog(): array
{
    return [
        'minimal' => [
            'workspace' => true,
            'membership' => true,
            'session' => true,
            'provider' => false,
            'credential' => false,
            'cache' => false,
            'uiContext' => false,
        ],
        'standard' => [
            'workspace' => true,
            'membership' => true,
            'session' => true,
            'provider' => true,
            'credential' => false,
            'cache' => false,
            'uiContext' => false,
        ],
        'full' => [
            'workspace' => true,
            'membership' => true,
            'session' => true,
            'provider' => true,
            'credential' => true,
            'cache' => true,
            'uiContext' => true,
        ],
    ];
}

/**
 * @return array<string, array{profile: string, overrides?: array{workspace?: bool, membership?: bool, session?: bool, provider?: bool, credential?: bool, cache?: bool, uiContext?: bool}, removalTrigger: string}>
 */
function createUserWithTenantLegacyProfileAliases(): array
{
    return [
        'provider-enabled' => [
            'profile' => 'standard',
            'removalTrigger' => 'Retire after the first fast-feedback and confidence migration packs use the canonical standard profile directly.',
        ],
        'credential-enabled' => [
            'profile' => 'full',
            'overrides' => [
                'cache' => false,
                'uiContext' => false,
            ],
            'removalTrigger' => 'Retire after the credential-dependent caller pack adopts createFullUserWithTenant() or fixtureProfile: full plus local overrides.',
        ],
        'ui-context' => [
            'profile' => 'full',
            'overrides' => [
                'provider' => false,
                'credential' => false,
            ],
            'removalTrigger' => 'Retire after UI-context callers switch to the canonical full profile or an explicit local UI-context helper.',
        ],
        'heavy' => [
            'profile' => 'full',
            'removalTrigger' => 'Retire after legacy heavy callers migrate to the canonical full profile.',
        ],
    ];
}

/**
 * @return array{requestedProfile: string, canonicalProfile: string, sideEffects: array{workspace: bool, membership: bool, session: bool, provider: bool, credential: bool, cache: bool, uiContext: bool}, legacyAlias: ?string, removalTrigger: ?string}
 */
function resolveCreateUserWithTenantProfile(string $fixtureProfile): array
{
    $catalog = createUserWithTenantProfileCatalog();

    if (array_key_exists($fixtureProfile, $catalog)) {
        return [
            'requestedProfile' => $fixtureProfile,
            'canonicalProfile' => $fixtureProfile,
            'sideEffects' => $catalog[$fixtureProfile],
            'legacyAlias' => null,
            'removalTrigger' => null,
        ];
    }

    $aliases = createUserWithTenantLegacyProfileAliases();

    if (! array_key_exists($fixtureProfile, $aliases)) {
        throw new \InvalidArgumentException(sprintf('Unknown fixture profile [%s].', $fixtureProfile));
    }

    $resolution = $aliases[$fixtureProfile];
    $canonicalProfile = $resolution['profile'];

    if (! array_key_exists($canonicalProfile, $catalog)) {
        throw new \InvalidArgumentException(sprintf('Unknown canonical fixture profile [%s].', $canonicalProfile));
    }

    return [
        'requestedProfile' => $fixtureProfile,
        'canonicalProfile' => $canonicalProfile,
        'sideEffects' => array_replace($catalog[$canonicalProfile], $resolution['overrides'] ?? []),
        'legacyAlias' => $fixtureProfile,
        'removalTrigger' => $resolution['removalTrigger'],
    ];
}

/**
 * @return array<string, array{workspace: bool, membership: bool, session: bool, provider: bool, credential: bool, cache: bool, uiContext: bool}>
 */
function createUserWithTenantProfiles(): array
{
    $profiles = createUserWithTenantProfileCatalog();

    foreach (createUserWithTenantLegacyProfileAliases() as $alias => $resolution) {
        $profiles[$alias] = array_replace(
            $profiles[$resolution['profile']],
            $resolution['overrides'] ?? [],
        );
    }

    return $profiles;
}

/**
 * @return array{0: User, 1: ManagedEnvironment}
 */
function createMinimalUserWithTenant(
    ?ManagedEnvironment $tenant = null,
    ?User $user = null,
    string $role = 'owner',
    ?string $workspaceRole = null,
    bool $ensureDefaultMicrosoftProviderConnection = false,
    string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
    bool $ensureDefaultCredential = false,
    ?bool $clearCapabilityCaches = null,
    ?bool $setUiContext = null,
): array {
    return createUserWithTenant(
        tenant: $tenant,
        user: $user,
        role: $role,
        workspaceRole: $workspaceRole,
        ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
        defaultProviderConnectionType: $defaultProviderConnectionType,
        fixtureProfile: 'minimal',
        ensureDefaultCredential: $ensureDefaultCredential,
        clearCapabilityCaches: $clearCapabilityCaches,
        setUiContext: $setUiContext,
    );
}

/**
 * @return array{0: User, 1: ManagedEnvironment}
 */
function createStandardUserWithTenant(
    ?ManagedEnvironment $tenant = null,
    ?User $user = null,
    string $role = 'owner',
    ?string $workspaceRole = null,
    bool $ensureDefaultMicrosoftProviderConnection = false,
    string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
    bool $ensureDefaultCredential = false,
    ?bool $clearCapabilityCaches = null,
    ?bool $setUiContext = null,
): array {
    return createUserWithTenant(
        tenant: $tenant,
        user: $user,
        role: $role,
        workspaceRole: $workspaceRole,
        ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
        defaultProviderConnectionType: $defaultProviderConnectionType,
        fixtureProfile: 'standard',
        ensureDefaultCredential: $ensureDefaultCredential,
        clearCapabilityCaches: $clearCapabilityCaches,
        setUiContext: $setUiContext,
    );
}

/**
 * @return array{0: User, 1: ManagedEnvironment}
 */
function createFullUserWithTenant(
    ?ManagedEnvironment $tenant = null,
    ?User $user = null,
    string $role = 'owner',
    ?string $workspaceRole = null,
    bool $ensureDefaultMicrosoftProviderConnection = false,
    string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
    bool $ensureDefaultCredential = false,
    ?bool $clearCapabilityCaches = null,
    ?bool $setUiContext = null,
): array {
    return createUserWithTenant(
        tenant: $tenant,
        user: $user,
        role: $role,
        workspaceRole: $workspaceRole,
        ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
        defaultProviderConnectionType: $defaultProviderConnectionType,
        fixtureProfile: 'full',
        ensureDefaultCredential: $ensureDefaultCredential,
        clearCapabilityCaches: $clearCapabilityCaches,
        setUiContext: $setUiContext,
    );
}

/**
 * @return array{0: User, 1: ManagedEnvironment}
 */
function createProviderEnabledUserWithTenant(
    ?ManagedEnvironment $tenant = null,
    ?User $user = null,
    string $role = 'owner',
    ?string $workspaceRole = null,
    bool $ensureDefaultMicrosoftProviderConnection = false,
    string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
    bool $ensureDefaultCredential = false,
    ?bool $clearCapabilityCaches = null,
    ?bool $setUiContext = null,
): array {
    return createUserWithTenant(
        tenant: $tenant,
        user: $user,
        role: $role,
        workspaceRole: $workspaceRole,
        ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
        defaultProviderConnectionType: $defaultProviderConnectionType,
        fixtureProfile: 'provider-enabled',
        ensureDefaultCredential: $ensureDefaultCredential,
        clearCapabilityCaches: $clearCapabilityCaches,
        setUiContext: $setUiContext,
    );
}

/**
 * @return array{0: User, 1: ManagedEnvironment}
 */
function createCredentialEnabledUserWithTenant(
    ?ManagedEnvironment $tenant = null,
    ?User $user = null,
    string $role = 'owner',
    ?string $workspaceRole = null,
    bool $ensureDefaultMicrosoftProviderConnection = false,
    string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
    bool $ensureDefaultCredential = false,
    ?bool $clearCapabilityCaches = null,
    ?bool $setUiContext = null,
): array {
    return createUserWithTenant(
        tenant: $tenant,
        user: $user,
        role: $role,
        workspaceRole: $workspaceRole,
        ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
        defaultProviderConnectionType: $defaultProviderConnectionType,
        fixtureProfile: 'credential-enabled',
        ensureDefaultCredential: $ensureDefaultCredential,
        clearCapabilityCaches: $clearCapabilityCaches,
        setUiContext: $setUiContext,
    );
}

/**
 * @return array{0: User, 1: ManagedEnvironment}
 */
function createUiContextUserWithTenant(
    ?ManagedEnvironment $tenant = null,
    ?User $user = null,
    string $role = 'owner',
    ?string $workspaceRole = null,
    bool $ensureDefaultMicrosoftProviderConnection = false,
    string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
    bool $ensureDefaultCredential = false,
    ?bool $clearCapabilityCaches = null,
    ?bool $setUiContext = null,
): array {
    return createUserWithTenant(
        tenant: $tenant,
        user: $user,
        role: $role,
        workspaceRole: $workspaceRole,
        ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
        defaultProviderConnectionType: $defaultProviderConnectionType,
        fixtureProfile: 'ui-context',
        ensureDefaultCredential: $ensureDefaultCredential,
        clearCapabilityCaches: $clearCapabilityCaches,
        setUiContext: $setUiContext,
    );
}

/**
 * @return array{0: User, 1: ManagedEnvironment}
 */
function createHeavyUserWithTenant(
    ?ManagedEnvironment $tenant = null,
    ?User $user = null,
    string $role = 'owner',
    ?string $workspaceRole = null,
    bool $ensureDefaultMicrosoftProviderConnection = false,
    string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
    bool $ensureDefaultCredential = false,
    ?bool $clearCapabilityCaches = null,
    ?bool $setUiContext = null,
): array {
    return createUserWithTenant(
        tenant: $tenant,
        user: $user,
        role: $role,
        workspaceRole: $workspaceRole,
        ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
        defaultProviderConnectionType: $defaultProviderConnectionType,
        fixtureProfile: 'heavy',
        ensureDefaultCredential: $ensureDefaultCredential,
        clearCapabilityCaches: $clearCapabilityCaches,
        setUiContext: $setUiContext,
    );
}

/**
 * @return array{0: User, 1: ManagedEnvironment}
 */
function createUserWithTenant(
    ?ManagedEnvironment $tenant = null,
    ?User $user = null,
    string $role = 'owner',
    ?string $workspaceRole = null,
    bool $ensureDefaultMicrosoftProviderConnection = false,
    string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
    string $fixtureProfile = 'minimal',
    bool $ensureDefaultCredential = false,
    ?bool $clearCapabilityCaches = null,
    ?bool $setUiContext = null,
): array {
    $resolvedProfile = resolveCreateUserWithTenantProfile($fixtureProfile);
    $profile = $resolvedProfile['sideEffects'];
    $user ??= User::factory()->create();
    $tenant ??= ManagedEnvironment::factory()->create();

    $workspaceRole ??= $role;

    $validWorkspaceRoles = array_map(
        static fn (\App\Support\Auth\WorkspaceRole $role): string => $role->value,
        \App\Support\Auth\WorkspaceRole::cases(),
    );

    if (! in_array($workspaceRole, $validWorkspaceRoles, true)) {
        $workspaceRole = \App\Support\Auth\WorkspaceRole::Owner->value;
    }

    $workspace = null;

    if ($tenant->workspace_id !== null) {
        $workspace = Workspace::query()->whereKey($tenant->workspace_id)->first();
    }

    if (! $workspace instanceof Workspace) {
        $workspace = Workspace::factory()->create();

        $tenant->forceFill([
            'workspace_id' => (int) $workspace->getKey(),
        ])->save();
    }

    if ($profile['membership']) {
        WorkspaceMembership::query()->updateOrCreate([
            'workspace_id' => (int) $workspace->getKey(),
            'user_id' => (int) $user->getKey(),
        ], [
            'role' => $workspaceRole,
        ]);
    }

    if ($profile['session']) {
        session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());
        $user->forceFill(['last_workspace_id' => (int) $workspace->getKey()])->save();
    }

    $user->tenants()->syncWithoutDetaching([
        $tenant->getKey() => ['role' => $role],
    ]);

    $shouldClearCapabilityCaches = $clearCapabilityCaches ?? $profile['cache'];

    if ($shouldClearCapabilityCaches) {
        app(CapabilityResolver::class)->clearCache();
        app(WorkspaceCapabilityResolver::class)->clearCache();
    }

    $shouldEnsureProviderConnection = $ensureDefaultMicrosoftProviderConnection || $profile['provider'];
    $shouldEnsureCredential = $ensureDefaultCredential || $profile['credential'];

    if ($shouldEnsureProviderConnection) {
        ensureDefaultProviderConnection(
            $tenant,
            'microsoft',
            $defaultProviderConnectionType,
            $shouldEnsureCredential,
        );
    }

    $shouldSetUiContext = $setUiContext ?? $profile['uiContext'];

    if ($shouldSetUiContext) {
        $tenant->makeCurrent();
        Filament::setTenant($tenant, true);
    }

    return [$user, $tenant];
}

function baselineCompareLandingLivewire(ManagedEnvironment $tenant, array $queryParams = []): mixed
{
    $manager = \Livewire\Livewire::withHeaders([
        'Referer' => \App\Support\ManagedEnvironmentLinks::baselineCompareUrl($tenant),
    ]);

    if ($queryParams !== []) {
        $manager = $manager->withQueryParams($queryParams);
    }

    return $manager->test(\App\Filament\Pages\BaselineCompareLanding::class, [
        'environment' => $tenant,
    ]);
}

/**
 * @return array{0: BaselineProfile, 1: BaselineSnapshot}
 */
function seedActiveBaselineForTenant(ManagedEnvironment $tenant): array
{
    $profile = BaselineProfile::factory()->active()->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

    $snapshot = BaselineSnapshot::factory()->complete()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'baseline_profile_id' => (int) $profile->getKey(),
    ]);

    $profile->forceFill([
        'active_snapshot_id' => (int) $snapshot->getKey(),
    ])->save();

    BaselineTenantAssignment::query()->updateOrCreate([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
    ], [
        'baseline_profile_id' => (int) $profile->getKey(),
        'override_scope_jsonb' => null,
    ]);

    return [$profile, $snapshot];
}

/**
 * @param  array<string, mixed>  $compareContext
 */
function seedBaselineCompareRun(
    ManagedEnvironment $tenant,
    BaselineProfile $profile,
    BaselineSnapshot $snapshot,
    array $compareContext = [],
    string $status = OperationRunStatus::Completed->value,
    string $outcome = OperationRunOutcome::Succeeded->value,
    ?\Carbon\CarbonInterface $completedAt = null,
): OperationRun {
    $completedAt ??= now();

    return OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => OperationRunType::BaselineCompare->value,
        'status' => $status,
        'outcome' => $outcome,
        'created_at' => $completedAt,
        'completed_at' => $status === OperationRunStatus::Completed->value ? $completedAt : null,
        'context' => [
            'baseline_profile_id' => (int) $profile->getKey(),
            'baseline_snapshot_id' => (int) $snapshot->getKey(),
            'baseline_compare' => $compareContext,
        ],
    ]);
}

/**
 * @return array<string, mixed>
 */
function workspaceOverviewCompareCoverage(): array
{
    return [
        'reason_code' => \App\Support\Baselines\BaselineCompareReasonCode::NoDriftDetected->value,
        'coverage' => [
            'effective_types' => ['deviceConfiguration'],
            'covered_types' => ['deviceConfiguration'],
            'uncovered_types' => [],
            'proof' => true,
        ],
    ];
}

function workspaceOverviewSeedQuietTenantTruth(ManagedEnvironment $tenant): void
{
    [$profile, $snapshot] = seedActiveBaselineForTenant($tenant);

    seedBaselineCompareRun($tenant, $profile, $snapshot, workspaceOverviewCompareCoverage());
}

/**
 * @param  array<string, mixed>  $backupSetAttributes
 * @param  array<string, mixed>  $itemAttributes
 */
function workspaceOverviewSeedHealthyBackup(
    ManagedEnvironment $tenant,
    array $backupSetAttributes = [],
    array $itemAttributes = [],
): BackupSet {
    $backupSet = BackupSet::factory()
        ->for($tenant)
        ->create(array_merge([
            'name' => 'Workspace overview healthy backup',
            'item_count' => 1,
            'completed_at' => now()->subMinutes(20),
        ], $backupSetAttributes));

    BackupItem::factory()
        ->for($tenant)
        ->for($backupSet)
        ->create(array_merge([
            'payload' => ['id' => 'workspace-overview-policy'],
            'metadata' => [],
            'assignments' => [],
        ], $itemAttributes));

    return $backupSet;
}

/**
 * @param  array<string, mixed>  $attributes
 */
function workspaceOverviewSeedRestoreHistory(
    ManagedEnvironment $tenant,
    BackupSet $backupSet,
    string $state = 'completed',
    array $attributes = [],
): RestoreRun {
    $factory = match ($state) {
        'failed' => RestoreRun::factory()->failedOutcome(),
        'partial' => RestoreRun::factory()->partialOutcome(),
        'follow_up' => RestoreRun::factory()->completedWithFollowUp(),
        default => RestoreRun::factory()->completedOutcome(),
    };

    return $factory
        ->for($tenant)
        ->for($backupSet)
        ->create(array_merge([
            'completed_at' => now()->subMinutes(10),
        ], $attributes));
}

/**
 * @return array{tenant: string}
 */
function filamentTenantRouteParams(ManagedEnvironment $tenant): array
{
    return ['tenant' => (string) $tenant->external_id];
}

function ensureDefaultProviderConnection(
    ManagedEnvironment $tenant,
    string $provider = 'microsoft',
    string $connectionType = ProviderConnectionType::Dedicated->value,
    bool $ensureCredential = true,
): ProviderConnection {
    $resolvedConnectionType = ProviderConnectionType::tryFrom($connectionType) ?? ProviderConnectionType::Dedicated;

    $connection = ProviderConnection::query()
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->where('provider', $provider)
        ->orderByDesc('is_default')
        ->orderBy('id')
        ->first();

    if (! $connection instanceof ProviderConnection) {
        $connectionFactory = ProviderConnection::factory();

        if ($resolvedConnectionType === ProviderConnectionType::Dedicated) {
            $connectionFactory = $connectionFactory->dedicated();
        }

        $connection = $connectionFactory->verifiedHealthy()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'provider' => $provider,
            'entra_tenant_id' => (string) ($tenant->managed_environment_id ?? fake()->uuid()),
            'connection_type' => $resolvedConnectionType->value,
            'is_default' => true,
        ]);
    } else {
        $entraTenantId = trim((string) $connection->entra_tenant_id);
        $currentConnectionType = $connection->connection_type instanceof ProviderConnectionType
            ? $connection->connection_type->value
            : (is_string($connection->connection_type) ? $connection->connection_type : null);
        $currentConsentStatus = $connection->consent_status instanceof ProviderConsentStatus
            ? $connection->consent_status->value
            : (is_string($connection->consent_status) ? $connection->consent_status : null);
        $currentVerificationStatus = $connection->verification_status instanceof ProviderVerificationStatus
            ? $connection->verification_status->value
            : (is_string($connection->verification_status) ? $connection->verification_status : null);

        $updates = [];

        if ($currentConnectionType !== $resolvedConnectionType->value) {
            $updates['connection_type'] = $resolvedConnectionType->value;
        }

        if (! $connection->is_default) {
            $updates['is_default'] = true;
        }

        if (! $connection->is_enabled) {
            $updates['is_enabled'] = true;
        }

        if ($currentConsentStatus !== ProviderConsentStatus::Granted->value) {
            $updates['consent_status'] = ProviderConsentStatus::Granted->value;
        }

        if ($currentVerificationStatus !== ProviderVerificationStatus::Healthy->value) {
            $updates['verification_status'] = ProviderVerificationStatus::Healthy->value;
        }

        if ($entraTenantId === '') {
            $updates['entra_tenant_id'] = (string) ($tenant->managed_environment_id ?? fake()->uuid());
        }

        if (! array_key_exists('consent_granted_at', $updates)) {
            $updates['consent_granted_at'] = now();
        }

        if (! array_key_exists('consent_last_checked_at', $updates)) {
            $updates['consent_last_checked_at'] = now();
        }

        if (! array_key_exists('last_health_check_at', $updates)) {
            $updates['last_health_check_at'] = now();
        }

        if (! array_key_exists('migration_review_required', $updates)) {
            $updates['migration_review_required'] = false;
        }

        if ($updates !== []) {
            $connection->forceFill($updates)->save();
            $connection->refresh();
        }
    }

    $credential = $connection->credential()->first();

    if ($resolvedConnectionType === ProviderConnectionType::Platform) {
        if ($credential instanceof ProviderCredential) {
            $credential->delete();
            $connection->refresh();
        }

        return $connection;
    }

    if (! $ensureCredential) {
        if ($credential instanceof ProviderCredential) {
            $credential->delete();
            $connection->refresh();
        }

        return $connection;
    }

    if (! $credential instanceof ProviderCredential) {
        ProviderCredential::factory()->create([
            'provider_connection_id' => (int) $connection->getKey(),
            'type' => ProviderCredentialKind::ClientSecret->value,
            'credential_kind' => ProviderCredentialKind::ClientSecret->value,
            'source' => ProviderCredentialSource::DedicatedManual->value,
            'last_rotated_at' => now(),
            'expires_at' => now()->addYear(),
            'payload' => [
                'client_id' => fake()->uuid(),
                'client_secret' => fake()->sha1(),
            ],
        ]);

        $connection->refresh();
    }

    return $connection;
}

if (! function_exists('spec283ConfiguredPermissionRows')) {
    function spec283ConfiguredPermissionRows(): array
    {
        return array_merge(
            config('intune_permissions.permissions', []),
            config('entra_permissions.permissions', []),
        );
    }
}

if (! function_exists('spec283SeedRequirementRows')) {
    function spec283SeedRequirementRows(ManagedEnvironment $tenant, array $requirementKeys, array $missingKeys = [], array $errorKeys = []): void
    {
        foreach (spec283ConfiguredPermissionRows() as $permission) {
            if (! is_array($permission)) {
                continue;
            }

            $mappedRequirementKeys = \App\Support\Verification\ManagedEnvironmentPermissionCheckClusters::requirementKeysForPermissionRow($permission);

            if (array_intersect($requirementKeys, $mappedRequirementKeys) === []) {
                continue;
            }

            $permissionKey = (string) ($permission['key'] ?? '');

            \App\Models\ManagedEnvironmentPermission::query()->updateOrCreate(
                [
                    'managed_environment_id' => (int) $tenant->getKey(),
                    'permission_key' => $permissionKey,
                    'workspace_id' => (int) $tenant->workspace_id,
                ],
                [
                    'status' => in_array($permissionKey, $errorKeys, true)
                        ? 'error'
                        : (in_array($permissionKey, $missingKeys, true) ? 'missing' : 'granted'),
                    'details' => ['source' => 'spec-283-test'],
                    'last_checked_at' => now(),
                ],
            );
        }
    }
}

/**
 * @param  array<string, mixed>  $permissionPayload
 * @param  array<string, mixed>  $rolePayload
 */
function seedEnvironmentReviewEvidence(
    ManagedEnvironment $tenant,
    array $permissionPayload = [],
    array $rolePayload = [],
    int $findingCount = 3,
    int $driftCount = 1,
    int $operationRunCount = 1,
): EvidenceSnapshot {
    StoredReport::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'report_type' => StoredReport::REPORT_TYPE_PERMISSION_POSTURE,
        'payload' => array_replace_recursive([
            'posture_score' => 86,
            'required_count' => 14,
            'granted_count' => 12,
            'permissions' => [
                ['key' => 'DeviceManagementConfiguration.ReadWrite.All', 'status' => 'granted'],
            ],
        ], $permissionPayload),
    ]);

    StoredReport::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'report_type' => StoredReport::REPORT_TYPE_ENTRA_ADMIN_ROLES,
        'payload' => array_replace_recursive([
            'roles' => [
                [
                    'displayName' => 'Global Administrator',
                    'userPrincipalName' => 'admin@contoso.com',
                ],
            ],
        ], $rolePayload),
    ]);

    Finding::factory()
        ->count($findingCount)
        ->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
        ]);

    Finding::factory()
        ->count($driftCount)
        ->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'finding_type' => Finding::FINDING_TYPE_DRIFT,
        ]);

    OperationRun::factory()
        ->count($operationRunCount)
        ->forTenant($tenant)
        ->create([
            'type' => OperationRunType::PolicySync->value,
        ]);

    /** @var EvidenceSnapshotService $service */
    $service = app(EvidenceSnapshotService::class);
    $payload = $service->buildSnapshotPayload($tenant);

    $snapshot = EvidenceSnapshot::query()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'status' => EvidenceSnapshotStatus::Active->value,
        'fingerprint' => $payload['fingerprint'],
        'completeness_state' => $payload['completeness'],
        'summary' => $payload['summary'],
        'generated_at' => now(),
    ]);

    foreach ($payload['items'] as $item) {
        $snapshot->items()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'dimension_key' => $item['dimension_key'],
            'state' => $item['state'],
            'required' => $item['required'],
            'source_kind' => $item['source_kind'],
            'source_record_type' => $item['source_record_type'],
            'source_record_id' => $item['source_record_id'],
            'source_fingerprint' => $item['source_fingerprint'],
            'measured_at' => $item['measured_at'],
            'freshness_at' => $item['freshness_at'],
            'summary_payload' => $item['summary_payload'],
            'sort_order' => $item['sort_order'],
        ]);
    }

    return $snapshot->load('items');
}

/**
 * @param  array<string, mixed>  $permissionPayload
 * @param  array<string, mixed>  $rolePayload
 */
function seedStaleEnvironmentReviewEvidence(
    ManagedEnvironment $tenant,
    array $permissionPayload = [],
    array $rolePayload = [],
    int $findingCount = 3,
    int $driftCount = 1,
    int $operationRunCount = 1,
    array $summaryOverrides = [],
): EvidenceSnapshot {
    $snapshot = seedEnvironmentReviewEvidence(
        tenant: $tenant,
        permissionPayload: $permissionPayload,
        rolePayload: $rolePayload,
        findingCount: $findingCount,
        driftCount: $driftCount,
        operationRunCount: $operationRunCount,
    );

    return restateEnvironmentReviewEvidenceSnapshot(
        $snapshot,
        EvidenceCompletenessState::Stale,
        array_replace([
            'missing_dimensions' => 0,
            'stale_dimensions' => 2,
        ], $summaryOverrides),
    );
}

/**
 * @param  array<string, mixed>  $permissionPayload
 * @param  array<string, mixed>  $rolePayload
 */
function seedPartialEnvironmentReviewEvidence(
    ManagedEnvironment $tenant,
    array $permissionPayload = [],
    array $rolePayload = [],
    int $findingCount = 3,
    int $driftCount = 1,
    int $operationRunCount = 1,
    array $summaryOverrides = [],
): EvidenceSnapshot {
    $snapshot = seedEnvironmentReviewEvidence(
        tenant: $tenant,
        permissionPayload: $permissionPayload,
        rolePayload: $rolePayload,
        findingCount: $findingCount,
        driftCount: $driftCount,
        operationRunCount: $operationRunCount,
    );

    return restateEnvironmentReviewEvidenceSnapshot(
        $snapshot,
        EvidenceCompletenessState::Partial,
        array_replace([
            'missing_dimensions' => 1,
            'stale_dimensions' => 0,
        ], $summaryOverrides),
    );
}

function composeEnvironmentReviewForTest(ManagedEnvironment $tenant, User $user, ?EvidenceSnapshot $snapshot = null): EnvironmentReview
{
    $snapshot ??= seedEnvironmentReviewEvidence($tenant);

    /** @var EnvironmentReviewService $service */
    $service = app(EnvironmentReviewService::class);
    $review = $service->create($tenant, $snapshot, $user);

    $review = $review->refresh();

    if ($review->generated_at === null || ! $review->sections()->exists()) {
        $review = $service->compose($review);
    }

    return $review->refresh();
}

/**
 * @param  array<string, mixed>  $summaryOverrides
 */
function restateEnvironmentReviewEvidenceSnapshot(
    EvidenceSnapshot $snapshot,
    EvidenceCompletenessState $completenessState,
    array $summaryOverrides = [],
): EvidenceSnapshot {
    $summary = is_array($snapshot->summary) ? $snapshot->summary : [];

    $summary = array_replace($summary, match ($completenessState) {
        EvidenceCompletenessState::Stale => [
            'dimension_count' => max(1, (int) ($summary['dimension_count'] ?? 5)),
            'missing_dimensions' => 0,
            'stale_dimensions' => max(1, (int) ($summary['stale_dimensions'] ?? 1)),
        ],
        EvidenceCompletenessState::Partial => [
            'dimension_count' => max(1, (int) ($summary['dimension_count'] ?? 5)),
            'missing_dimensions' => max(1, (int) ($summary['missing_dimensions'] ?? 1)),
            'stale_dimensions' => 0,
        ],
        EvidenceCompletenessState::Missing => [
            'dimension_count' => (int) ($summary['dimension_count'] ?? 0),
            'missing_dimensions' => max(1, (int) ($summary['missing_dimensions'] ?? 1)),
            'stale_dimensions' => 0,
        ],
        EvidenceCompletenessState::Complete => [
            'dimension_count' => max(1, (int) ($summary['dimension_count'] ?? 5)),
            'missing_dimensions' => 0,
            'stale_dimensions' => 0,
        ],
    });

    $summary = array_replace_recursive($summary, $summaryOverrides);

    $snapshot->forceFill([
        'completeness_state' => $completenessState->value,
        'summary' => $summary,
    ])->save();

    $primaryItem = $snapshot->items()->where('required', true)->orderBy('sort_order')->first();

    if ($primaryItem !== null) {
        $primaryItem->forceFill([
            'state' => $completenessState->value,
            'measured_at' => $completenessState === EvidenceCompletenessState::Stale
                ? now()->subDays(45)
                : ($primaryItem->measured_at ?? now()),
            'freshness_at' => $completenessState === EvidenceCompletenessState::Stale
                ? now()->subDays(45)
                : ($primaryItem->freshness_at ?? now()),
        ])->save();
    }

    return $snapshot->fresh('items');
}

function setAdminEnvironmentContext(ManagedEnvironment $tenant): void
{
    setAdminPanelContext($tenant);
}

/**
 * Set the workspace-first admin panel context for tests. There is no TenantPanel compatibility helper.
 */
function setAdminPanelContext(?ManagedEnvironment $tenant = null): void
{
    if ($tenant instanceof ManagedEnvironment) {
        $tenant->makeCurrent();
    }

    Filament::setCurrentPanel('admin');
    Filament::setTenant($tenant, true);
    Filament::bootCurrentPanel();
}

/**
 * @param  array<string, mixed>  $attributes
 */
function createOnboardingDraft(array $attributes = []): ManagedEnvironmentOnboardingSession
{
    $workspace = $attributes['workspace'] ?? Workspace::factory()->create();
    $tenant = $attributes['tenant'] ?? null;
    $startedBy = $attributes['started_by'] ?? User::factory()->create();
    $updatedBy = $attributes['updated_by'] ?? $startedBy;

    foreach ([$startedBy, $updatedBy] as $member) {
        if (! $member instanceof User) {
            continue;
        }

        WorkspaceMembership::query()->firstOrCreate([
            'workspace_id' => (int) $workspace->getKey(),
            'user_id' => (int) $member->getKey(),
        ], [
            'role' => 'owner',
        ]);
    }

    $factory = ManagedEnvironmentOnboardingSession::factory()
        ->forWorkspace($workspace)
        ->startedBy($startedBy)
        ->updatedBy($updatedBy);

    if ($tenant instanceof ManagedEnvironment) {
        $factory = $factory->forTenant($tenant);
    }

    if (($attributes['status'] ?? null) === 'completed') {
        $factory = $factory->completed();
    }

    if (($attributes['status'] ?? null) === 'cancelled') {
        $factory = $factory->cancelled();
    }

    unset(
        $attributes['workspace'],
        $attributes['tenant'],
        $attributes['started_by'],
        $attributes['updated_by'],
        $attributes['status'],
    );

    return $factory->create($attributes);
}

/**
 * @return list<TenantActionDescriptor>
 */
function tenantActionCatalog(ManagedEnvironment $tenant, TenantActionSurface $surface, ?User $user = null): array
{
    return app(TenantActionPolicySurface::class)->catalogForTenant($tenant, $surface, $user);
}

/**
 * @param  list<TenantActionDescriptor>  $actions
 * @return list<string>
 */
function tenantActionKeys(array $actions): array
{
    return array_values(array_map(
        static fn (TenantActionDescriptor $action): string => $action->key,
        $actions,
    ));
}

function ensureDefaultPlatformProviderConnection(ManagedEnvironment $tenant, string $provider = 'microsoft'): ProviderConnection
{
    return ensureDefaultProviderConnection($tenant, $provider, ProviderConnectionType::Platform->value);
}

function ensureDefaultDedicatedProviderConnection(ManagedEnvironment $tenant, string $provider = 'microsoft'): ProviderConnection
{
    return ensureDefaultProviderConnection($tenant, $provider, ProviderConnectionType::Dedicated->value);
}

/**
 * @param  array<string, mixed>  $snapshot
 * @param  array<int, array<string, mixed>>  $assignments
 * @param  array<string, mixed>  $scopeTags
 * @param  array<string, array<string, string>>  $secretFingerprints
 */
function expectedPolicyVersionContentHash(
    array $snapshot,
    string $policyType,
    ?string $platform = null,
    array $assignments = [],
    array $scopeTags = [],
    array $secretFingerprints = [],
    ?int $redactionVersion = 1,
): string {
    return app(\App\Services\Drift\DriftHasher::class)->hashNormalized([
        'settings' => app(\App\Services\Drift\Normalizers\SettingsNormalizer::class)->normalizeForDiff(
            $snapshot,
            $policyType,
            $platform,
        ),
        'assignments' => app(\App\Services\Drift\Normalizers\AssignmentsNormalizer::class)->normalizeForDiff($assignments),
        'scope_tag_ids' => app(\App\Services\Drift\Normalizers\ScopeTagsNormalizer::class)->normalizeIds($scopeTags),
        'secret_fingerprints' => [
            'snapshot' => is_array($secretFingerprints['snapshot'] ?? null) ? $secretFingerprints['snapshot'] : [],
            'assignments' => is_array($secretFingerprints['assignments'] ?? null) ? $secretFingerprints['assignments'] : [],
            'scope_tags' => is_array($secretFingerprints['scope_tags'] ?? null) ? $secretFingerprints['scope_tags'] : [],
        ],
        'redaction_version' => $redactionVersion,
    ]);
}
