<?php

use App\Models\AuditLog;
use App\Models\OperationRun;
use App\Models\ManagedEnvironment;
use App\Models\Workspace;
use Illuminate\Support\Facades\DB;

it('backfills missing workspace_id values for tenant-owned rows', function (): void {
    $workspace = Workspace::factory()->create();

    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
    ]);

    DB::table('policies')->insert([
        [
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => null,
            'external_id' => 'legacy-policy-a',
            'policy_type' => 'settingsCatalogPolicy',
            'platform' => 'windows',
            'display_name' => 'Legacy Policy A',
            'metadata' => json_encode([], JSON_THROW_ON_ERROR),
            'last_synced_at' => now(),
            'created_at' => now(),
            'updated_at' => now(),
        ],
        [
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => null,
            'external_id' => 'legacy-policy-b',
            'policy_type' => 'settingsCatalogPolicy',
            'platform' => 'windows',
            'display_name' => 'Legacy Policy B',
            'metadata' => json_encode([], JSON_THROW_ON_ERROR),
            'last_synced_at' => now(),
            'created_at' => now(),
            'updated_at' => now(),
        ],
    ]);

    $this->artisan('tenantpilot:backfill-workspace-ids', [
        '--table' => 'policies',
        '--batch-size' => 1,
    ])->assertSuccessful();

    $missingAfter = DB::table('policies')
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->whereNull('workspace_id')
        ->count();

    expect($missingAfter)->toBe(0);

    $workspaceIds = DB::table('policies')
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->pluck('workspace_id')
        ->map(static fn (mixed $workspaceId): int => (int) $workspaceId)
        ->unique()
        ->values()
        ->all();

    expect($workspaceIds)->toBe([(int) $workspace->getKey()]);

    $run = OperationRun::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->where('type', 'workspace_isolation_backfill_workspace_ids')
        ->latest('id')
        ->first();

    expect($run)->not->toBeNull();
    expect((int) data_get($run?->summary_counts, 'processed', 0))->toBe(2);

    $actions = AuditLog::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->pluck('action')
        ->all();

    expect($actions)->toContain('workspace_isolation.backfill_workspace_ids.started');
    expect($actions)->toContain('workspace_isolation.backfill_workspace_ids.dispatched');
});

it('is idempotent when re-run after backfill', function (): void {
    $workspace = Workspace::factory()->create();

    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
    ]);

    DB::table('policies')->insert([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => null,
        'external_id' => 'legacy-policy-retry',
        'policy_type' => 'settingsCatalogPolicy',
        'platform' => 'windows',
        'display_name' => 'Legacy Retry Policy',
        'metadata' => json_encode([], JSON_THROW_ON_ERROR),
        'last_synced_at' => now(),
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $this->artisan('tenantpilot:backfill-workspace-ids', ['--table' => 'policies'])->assertSuccessful();

    $this->artisan('tenantpilot:backfill-workspace-ids', ['--table' => 'policies'])
        ->expectsOutputToContain('No rows require workspace_id backfill.')
        ->assertSuccessful();

    $missingAfter = DB::table('policies')
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->whereNull('workspace_id')
        ->count();

    expect($missingAfter)->toBe(0);
});

it('aborts and reports when tenant to workspace mapping is unresolvable', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    $tenant->forceFill(['workspace_id' => null])->save();

    DB::table('policies')->insert([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => null,
        'external_id' => 'legacy-policy-unresolvable',
        'policy_type' => 'settingsCatalogPolicy',
        'platform' => 'windows',
        'display_name' => 'Legacy Unresolvable Policy',
        'metadata' => json_encode([], JSON_THROW_ON_ERROR),
        'last_synced_at' => now(),
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $this->artisan('tenantpilot:backfill-workspace-ids', ['--table' => 'policies'])
        ->expectsOutputToContain('Unresolvable tenant->workspace mapping')
        ->assertFailed();

    $missingAfter = DB::table('policies')
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->whereNull('workspace_id')
        ->count();

    expect($missingAfter)->toBe(1);
});
