<?php

declare(strict_types=1);

use App\Models\AuditLog;
use App\Models\BaselineProfile;
use App\Models\Workspace;
use Illuminate\Support\Facades\DB;

function spec202ForceLegacyBaselineScope(BaselineProfile $profile, array $scope): void
{
    DB::table('baseline_profiles')
        ->where('id', (int) $profile->getKey())
        ->update([
            'scope_jsonb' => json_encode($scope, JSON_THROW_ON_ERROR),
            'updated_at' => now(),
        ]);
}

it('previews only legacy baseline profile scope rows in mixed datasets without mutating them', 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]],
    ]);

    $workspace = Workspace::factory()->create();

    $legacyProfile = BaselineProfile::factory()->active()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'name' => 'Legacy preview profile',
    ]);
    $canonicalProfile = BaselineProfile::factory()->active()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'name' => 'Canonical preview profile',
        'scope_jsonb' => [
            'version' => 2,
            'entries' => [
                [
                    'domain_key' => 'intune',
                    'subject_class' => 'policy',
                    'subject_type_keys' => ['deviceCompliancePolicy'],
                    'filters' => [],
                ],
            ],
        ],
    ]);

    spec202ForceLegacyBaselineScope($legacyProfile, [
        'policy_types' => ['deviceConfiguration'],
        'foundation_types' => [],
    ]);

    $this->artisan('tenantpilot:baseline-scope-v2:backfill', [
        '--workspace' => (string) $workspace->getKey(),
    ])
        ->expectsOutputToContain('Mode: preview')
        ->expectsOutputToContain('Scope surface: baseline_profiles_only')
        ->expectsOutputToContain('Candidate count: 1')
        ->expectsOutputToContain('Rewritten count: 0')
        ->expectsOutputToContain('Audit logged: no')
        ->expectsOutputToContain('Legacy preview profile')
        ->assertSuccessful();

    $legacyProfile->refresh();
    $canonicalProfile->refresh();

    expect($legacyProfile->rawScopeJsonb())->toBe([
        'policy_types' => ['deviceConfiguration'],
        'foundation_types' => [],
    ])->and($canonicalProfile->rawScopeJsonb())->toBe([
        'version' => 2,
        'entries' => [
            [
                'domain_key' => 'intune',
                'subject_class' => 'policy',
                'subject_type_keys' => ['deviceCompliancePolicy'],
                'filters' => [],
            ],
        ],
    ]);
});

it('requires explicit write confirmation before mutating baseline profile scope rows', function (): void {
    $workspace = Workspace::factory()->create();

    $profile = BaselineProfile::factory()->active()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'name' => 'Legacy confirm profile',
    ]);

    spec202ForceLegacyBaselineScope($profile, [
        'policy_types' => ['deviceConfiguration'],
        'foundation_types' => [],
    ]);

    $this->artisan('tenantpilot:baseline-scope-v2:backfill', [
        '--workspace' => (string) $workspace->getKey(),
        '--write' => true,
    ])
        ->expectsOutputToContain('Explicit write confirmation required.')
        ->assertFailed();

    $profile->refresh();

    expect($profile->rawScopeJsonb())->toBe([
        'policy_types' => ['deviceConfiguration'],
        'foundation_types' => [],
    ]);
});

it('rewrites legacy baseline profile scopes to canonical v2, logs audits, and stays idempotent on rerun', function (): void {
    config()->set('tenantpilot.supported_policy_types', [
        ['type' => 'deviceConfiguration', 'label' => 'Device Configuration'],
        ['type' => 'deviceCompliancePolicy', 'label' => 'Device Compliance'],
    ]);

    $workspace = Workspace::factory()->create();

    $profile = BaselineProfile::factory()->active()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'name' => 'Legacy commit profile',
    ]);

    spec202ForceLegacyBaselineScope($profile, [
        'policy_types' => ['deviceConfiguration'],
        'foundation_types' => [],
    ]);

    $this->artisan('tenantpilot:baseline-scope-v2:backfill', [
        '--workspace' => (string) $workspace->getKey(),
        '--write' => true,
        '--confirm-write' => true,
    ])
        ->expectsOutputToContain('Mode: commit')
        ->expectsOutputToContain('Candidate count: 1')
        ->expectsOutputToContain('Rewritten count: 1')
        ->expectsOutputToContain('Audit logged: yes')
        ->assertSuccessful();

    $profile->refresh();

    expect($profile->rawScopeJsonb())->toBe([
        'version' => 2,
        'entries' => [
            [
                'domain_key' => 'intune',
                'subject_class' => 'policy',
                'subject_type_keys' => ['deviceConfiguration'],
                'filters' => [],
            ],
        ],
    ])->and($profile->requiresScopeSaveForward())->toBeFalse();

    $this->assertDatabaseHas('audit_logs', [
        'workspace_id' => (int) $workspace->getKey(),
        'action' => 'baseline_profile.scope_backfilled',
        'resource_type' => 'baseline_profile',
        'resource_id' => (string) $profile->getKey(),
    ]);

    $auditLog = AuditLog::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->where('action', 'baseline_profile.scope_backfilled')
        ->latest('id')
        ->first();

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

    $this->artisan('tenantpilot:baseline-scope-v2:backfill', [
        '--workspace' => (string) $workspace->getKey(),
    ])
        ->expectsOutputToContain('Candidate count: 0')
        ->expectsOutputToContain('No baseline profile scope rows require backfill.')
        ->assertSuccessful();
});