<?php

use App\Filament\Pages\BaselineCompareLanding;
use App\Jobs\CompareBaselineToTenantJob;
use App\Livewire\BulkOperationProgress;
use App\Models\BaselineProfile;
use App\Models\BaselineSnapshot;
use App\Models\BaselineTenantAssignment;
use App\Models\OperationRun;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
use App\Support\OpsUx\OpsUxBrowserEvents;
use Filament\Facades\Filament;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;

it('redirects unauthenticated users (302)', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->get(BaselineCompareLanding::getUrl(tenant: $tenant, panel: 'tenant'))
        ->assertStatus(302);
});

it('returns 404 for authenticated users not entitled to the tenant', function (): void {
    [$member, $tenant] = createUserWithTenant(role: 'owner');
    $nonMember = \App\Models\User::factory()->create();

    $this->actingAs($nonMember)
        ->get(BaselineCompareLanding::getUrl(tenant: $tenant, panel: 'tenant'))
        ->assertNotFound();
});

it('does not start baseline compare for members missing tenant.sync', function (): void {
    Queue::fake();

    [$user, $tenant] = createUserWithTenant(role: 'readonly');
    $this->actingAs($user);

    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    $profile = BaselineProfile::factory()->active()->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

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

    $profile->update(['active_snapshot_id' => (int) $snapshot->getKey()]);

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

    Livewire::test(BaselineCompareLanding::class)
        ->assertActionVisible('compareNow')
        ->assertActionDisabled('compareNow')
        ->callAction('compareNow')
        ->assertStatus(200);

    Queue::assertNotPushed(CompareBaselineToTenantJob::class);
});

it('dispatches ops-ux run-enqueued after starting baseline compare', function (): void {
    Queue::fake();
    config()->set('tenantpilot.baselines.full_content_capture.enabled', true);

    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    $profile = BaselineProfile::factory()->active()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'capture_mode' => \App\Support\Baselines\BaselineCaptureMode::FullContent->value,
    ]);

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

    $profile->update(['active_snapshot_id' => (int) $snapshot->getKey()]);

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

    Livewire::test(BaselineCompareLanding::class)
        ->assertActionHasLabel('compareNow', 'Compare now (full content)')
        ->callAction('compareNow')
        ->assertDispatchedTo(BulkOperationProgress::class, OpsUxBrowserEvents::RunEnqueued, tenantId: (int) $tenant->getKey());

    Queue::assertPushed(CompareBaselineToTenantJob::class);

    $run = OperationRun::query()
        ->where('tenant_id', (int) $tenant->getKey())
        ->where('type', 'baseline_compare')
        ->latest('id')
        ->first();

    expect($run)->not->toBeNull();
    expect($run?->status)->toBe('queued');
});

it('does not start full-content baseline compare when rollout is disabled', function (): void {
    Queue::fake();
    config()->set('tenantpilot.baselines.full_content_capture.enabled', false);

    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    $profile = BaselineProfile::factory()->active()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'capture_mode' => \App\Support\Baselines\BaselineCaptureMode::FullContent->value,
    ]);

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

    $profile->update(['active_snapshot_id' => (int) $snapshot->getKey()]);

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

    Livewire::test(BaselineCompareLanding::class)
        ->assertActionHasLabel('compareNow', 'Compare now (full content)')
        ->assertActionEnabled('compareNow')
        ->callAction('compareNow')
        ->assertNotified('Cannot start comparison')
        ->assertStatus(200);

    Queue::assertNotPushed(CompareBaselineToTenantJob::class);
    expect(OperationRun::query()->where('type', 'baseline_compare')->count())->toBe(0);
});

it('can refresh stats without calling mount directly', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    Livewire::test(BaselineCompareLanding::class)
        ->call('refreshStats')
        ->assertStatus(200);
});

it('exposes full coverage + fidelity context in stats', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    $profile = BaselineProfile::factory()->active()->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

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

    $profile->update(['active_snapshot_id' => (int) $snapshot->getKey()]);

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

    $compareRun = OperationRun::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => OperationRunType::BaselineCompare->value,
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Succeeded->value,
        'completed_at' => now(),
        'context' => [
            'baseline_profile_id' => (int) $profile->getKey(),
            'baseline_snapshot_id' => (int) $snapshot->getKey(),
            'baseline_compare' => [
                'coverage' => [
                    'effective_types' => ['deviceConfiguration'],
                    'covered_types' => ['deviceConfiguration'],
                    'uncovered_types' => [],
                    'proof' => true,
                ],
                'fidelity' => 'meta',
            ],
        ],
    ]);

    Livewire::test(BaselineCompareLanding::class)
        ->call('refreshStats')
        ->assertSet('operationRunId', (int) $compareRun->getKey())
        ->assertSet('coverageStatus', 'ok')
        ->assertSet('uncoveredTypesCount', 0)
        ->assertSet('fidelity', 'meta');
});

it('exposes coverage warning context in stats', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    $profile = BaselineProfile::factory()->active()->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

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

    $profile->update(['active_snapshot_id' => (int) $snapshot->getKey()]);

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

    $compareRun = OperationRun::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => OperationRunType::BaselineCompare->value,
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::PartiallySucceeded->value,
        'completed_at' => now(),
        'context' => [
            'baseline_profile_id' => (int) $profile->getKey(),
            'baseline_snapshot_id' => (int) $snapshot->getKey(),
            'baseline_compare' => [
                'coverage' => [
                    'effective_types' => ['deviceConfiguration', 'deviceCompliancePolicy'],
                    'covered_types' => ['deviceConfiguration'],
                    'uncovered_types' => ['deviceCompliancePolicy'],
                    'proof' => true,
                ],
                'fidelity' => 'meta',
            ],
        ],
    ]);

    Livewire::test(BaselineCompareLanding::class)
        ->call('refreshStats')
        ->assertSet('operationRunId', (int) $compareRun->getKey())
        ->assertSet('coverageStatus', 'warning')
        ->assertSet('uncoveredTypesCount', 1)
        ->assertSet('uncoveredTypes', ['deviceCompliancePolicy'])
        ->assertSet('fidelity', 'meta');
});
