<?php

declare(strict_types=1);

use App\Filament\Resources\BaselineProfileResource;
use App\Filament\Resources\BaselineProfileResource\Pages\CreateBaselineProfile;
use App\Filament\Resources\BaselineProfileResource\Pages\EditBaselineProfile;
use App\Filament\Resources\BaselineProfileResource\Pages\ViewBaselineProfile;
use App\Models\BaselineProfile;
use App\Support\Baselines\BaselineProfileStatus;
use App\Support\Governance\GovernanceSubjectTaxonomyRegistry;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Support\Facades\App;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\DB;
use Livewire\Livewire;

it('persists canonical v2 scope when creating a baseline profile through the current selectors', function (): void {
    config()->set('tenantpilot.supported_policy_types', [
        ['type' => 'deviceConfiguration', 'label' => 'Device Configuration'],
        ['type' => 'deviceCompliancePolicy', 'label' => 'Device Compliance'],
    ]);
    config()->set('tenantpilot.foundation_types', [
        ['type' => 'assignmentFilter', 'label' => 'Assignment Filter', 'baseline_compare' => ['supported' => true]],
        ['type' => 'intuneRoleAssignment', 'label' => 'Intune RBAC Role Assignment', 'baseline_compare' => ['supported' => false]],
    ]);

    [$user, $tenant] = createUserWithTenant(role: 'owner');
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);

    Livewire::actingAs($user)
        ->test(CreateBaselineProfile::class)
        ->fillForm([
            'name' => 'Canonical baseline profile',
            'scope_jsonb.policy_types' => ['deviceConfiguration'],
            'scope_jsonb.foundation_types' => ['assignmentFilter'],
        ])
        ->call('create')
        ->assertHasNoFormErrors()
        ->assertNotified();

    $profile = BaselineProfile::query()
        ->where('workspace_id', (int) $tenant->workspace_id)
        ->where('name', 'Canonical baseline profile')
        ->sole();

    expect($profile->scope_jsonb)->toBe([
        'policy_types' => ['deviceConfiguration'],
        'foundation_types' => ['assignmentFilter'],
    ])->and($profile->status)->toBe(BaselineProfileStatus::Draft);

    expect($profile->canonicalScopeJsonb())->toBe([
        'version' => 2,
        'entries' => [
            [
                'domain_key' => 'intune',
                'subject_class' => 'policy',
                'subject_type_keys' => ['deviceConfiguration'],
                'filters' => [],
            ],
            [
                'domain_key' => 'platform_foundation',
                'subject_class' => 'configuration_resource',
                'subject_type_keys' => ['assignmentFilter'],
                'filters' => [],
            ],
        ],
    ]);
});

it('normalizes legacy scope on read and saves it forward as canonical v2 on edit', function (): void {
    config()->set('tenantpilot.supported_policy_types', [
        ['type' => 'deviceConfiguration', 'label' => 'Device Configuration'],
        ['type' => 'deviceCompliancePolicy', 'label' => 'Device Compliance'],
    ]);
    config()->set('tenantpilot.foundation_types', [
        ['type' => 'assignmentFilter', 'label' => 'Assignment Filter', 'baseline_compare' => ['supported' => true]],
    ]);

    [$user, $tenant] = createUserWithTenant(role: 'owner');
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);

    $profileId = BaselineProfile::query()->insertGetId([
        'workspace_id' => (int) $tenant->workspace_id,
        'name' => 'Legacy baseline profile',
        'description' => null,
        'version_label' => null,
        'status' => BaselineProfileStatus::Active->value,
        'capture_mode' => 'opportunistic',
        'scope_jsonb' => json_encode([
            'policy_types' => [],
            'foundation_types' => ['assignmentFilter'],
        ], JSON_THROW_ON_ERROR),
        'active_snapshot_id' => null,
        'created_by_user_id' => (int) $user->getKey(),
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $profile = BaselineProfile::query()->findOrFail($profileId);

    expect($profile->normalizedScope()->normalizationLineage())->toMatchArray([
        'source_shape' => 'legacy',
        'normalized_on_read' => true,
        'save_forward_required' => true,
        'legacy_keys_present' => ['policy_types', 'foundation_types'],
    ])->and($profile->scope_jsonb)->toBe([
        'policy_types' => [],
        'foundation_types' => ['assignmentFilter'],
    ]);

    Livewire::actingAs($user)
        ->test(EditBaselineProfile::class, ['record' => $profileId])
        ->fillForm([
            'description' => 'Updated after normalization',
        ])
        ->call('save')
        ->assertHasNoFormErrors()
        ->assertNotified();

    $profile->refresh();
    $registry = app(GovernanceSubjectTaxonomyRegistry::class);

    expect($profile->canonicalScopeJsonb())->toBe([
        'version' => 2,
        'entries' => [
            [
                'domain_key' => 'intune',
                'subject_class' => 'policy',
                'subject_type_keys' => $registry->activeLegacyBucketKeys('policy_types'),
                'filters' => [],
            ],
            [
                'domain_key' => 'platform_foundation',
                'subject_class' => 'configuration_resource',
                'subject_type_keys' => ['assignmentFilter'],
                'filters' => [],
            ],
        ],
    ])->and($profile->normalizedScope()->normalizationLineage())->toMatchArray([
        'source_shape' => 'canonical_v2',
        'normalized_on_read' => false,
        'save_forward_required' => false,
    ]);
});

it('summarizes governed subjects, readiness, and save-forward feedback for current selector payloads', function (): void {
    App::setLocale('en');

    config()->set('tenantpilot.supported_policy_types', [
        ['type' => 'deviceConfiguration', 'label' => 'Device Configuration'],
        ['type' => 'deviceCompliancePolicy', 'label' => 'Device Compliance'],
    ]);
    config()->set('tenantpilot.foundation_types', [
        ['type' => 'assignmentFilter', 'label' => 'Assignment Filter', 'baseline_compare' => ['supported' => true]],
    ]);

    $payload = [
        'policy_types' => ['deviceConfiguration'],
        'foundation_types' => ['assignmentFilter'],
    ];

    expect(BaselineProfileResource::scopeSummaryText($payload))
        ->toBe(__('localization.policy.taxonomy.policies').': Device Configuration; Platform foundation configuration resources: Assignment Filter')
        ->and(BaselineProfileResource::scopeSupportReadinessText($payload))
        ->toBe('Capture: ready. Compare: ready.')
        ->and(BaselineProfileResource::scopeSelectionFeedbackText($payload))
        ->toBe('This Intune-first selection will be saved forward as canonical governed-subject scope V2.');
});

it('shows normalization lineage on the baseline profile detail surface before a legacy row is saved forward', function (): void {
    App::setLocale('en');

    config()->set('tenantpilot.supported_policy_types', [
        ['type' => 'deviceConfiguration', 'label' => 'Device Configuration'],
        ['type' => 'deviceCompliancePolicy', 'label' => 'Device Compliance'],
    ]);

    [$user, $tenant] = createUserWithTenant(role: 'owner');
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);

    $profileId = BaselineProfile::query()->insertGetId([
        'workspace_id' => (int) $tenant->workspace_id,
        'name' => 'Legacy lineage profile',
        'description' => null,
        'version_label' => null,
        'status' => BaselineProfileStatus::Active->value,
        'capture_mode' => 'opportunistic',
        'scope_jsonb' => json_encode([
            'policy_types' => ['deviceConfiguration'],
            'foundation_types' => [],
        ], JSON_THROW_ON_ERROR),
        'active_snapshot_id' => null,
        'created_by_user_id' => (int) $user->getKey(),
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    Livewire::actingAs($user)
        ->test(ViewBaselineProfile::class, ['record' => $profileId])
        ->assertSee('Governed subject summary')
        ->assertSee(__('localization.policy.taxonomy.policies').': Device Configuration')
        ->assertSee('Legacy Intune buckets are being normalized and will be saved forward as canonical V2 on the next successful save.');
});

it('rejects unsupported canonical filters when creating a baseline profile', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);

    $component = Livewire::actingAs($user)
        ->test(CreateBaselineProfile::class);

    $page = $component->instance();
    $method = new \ReflectionMethod($page, 'mutateFormDataBeforeCreate');
    $method->setAccessible(true);

    expect(fn () => $method->invoke($page, [
        'name' => 'Invalid filtered baseline',
        'scope_jsonb' => [
            'version' => 2,
            'entries' => [
                [
                    'domain_key' => 'intune',
                    'subject_class' => 'policy',
                    'subject_type_keys' => ['deviceConfiguration'],
                    'filters' => ['tenant_ids' => ['tenant-a']],
                ],
            ],
        ],
    ]))->toThrow(ValidationException::class, 'Filters are not supported');

    expect(BaselineProfile::query()->where('name', 'Invalid filtered baseline')->exists())->toBeFalse();
});
