<?php

declare(strict_types=1);

use App\Filament\Pages\CrossEnvironmentComparePage;
use App\Jobs\Operations\CrossEnvironmentPromotionExecutionJob;
use App\Models\OperationRun;
use Filament\Actions\Action;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;
use Tests\Feature\Concerns\BuildsPortfolioCompareFixtures;

uses(RefreshDatabase::class, BuildsPortfolioCompareFixtures::class);

it('requires a current preflight and queues only ready subjects into the promotion run', function (): void {
    Queue::fake();

    $fixture = $this->makeCrossEnvironmentCompareFixture();

    $this->createPortfolioCompareSubject(
        tenant: $fixture['sourceEnvironment'],
        displayName: 'Promotable Policy',
        snapshot: ['settings' => [['key' => 'wifi', 'value' => 1]]],
    );
    $blocked = $this->createPortfolioCompareSubject(
        tenant: $fixture['sourceEnvironment'],
        displayName: 'Blocked Policy',
        snapshot: ['settings' => [['key' => 'blocked', 'value' => 1]]],
    );
    $blocked['version']->delete();
    $this->createPortfolioCompareSubject(
        tenant: $fixture['sourceEnvironment'],
        displayName: 'Manual Policy',
        snapshot: ['settings' => [['key' => 'manual', 'value' => 1]]],
    );
    $this->createPortfolioCompareSubject(
        tenant: $fixture['targetEnvironment'],
        displayName: 'Manual Policy',
        snapshot: ['settings' => [['key' => 'manual', 'value' => 1]]],
    );
    $this->createPortfolioCompareSubject(
        tenant: $fixture['targetEnvironment'],
        displayName: 'Manual Policy',
        snapshot: ['settings' => [['key' => 'manual', 'value' => 2]]],
    );

    $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);

    $query = [
        'source_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
        'target_environment_id' => (int) $fixture['targetEnvironment']->getKey(),
        'policy_type' => ['deviceConfiguration'],
    ];

    $component = Livewire::withQueryParams($query)
        ->actingAs($fixture['user'])
        ->test(CrossEnvironmentComparePage::class)
        ->call('executePromotion')
        ->assertNotified('Promotion execution unavailable');

    expect(OperationRun::query()->count())->toBe(0);

    $component
        ->call('generatePromotionPreflight')
        ->assertActionVisible('executePromotion')
        ->mountAction('executePromotion')
        ->callMountedAction()
        ->assertHasNoActionErrors();

    $run = OperationRun::query()->latest('id')->first();

    expect($run)
        ->not->toBeNull()
        ->and($run?->type)->toBe('promotion.execute')
        ->and(data_get($run?->context, 'promotion_execution.plan.summary.ready'))->toBe(1)
        ->and(data_get($run?->context, 'promotion_execution.plan.summary.excluded'))->toBe(2)
        ->and(data_get($run?->context, 'promotion_execution.plan.items.0.display_name'))->toBe('Promotable Policy')
        ->and(data_get($run?->context, 'promotion_execution.plan.items.0.execution_action'))->toBe('create_missing')
        ->and(collect(data_get($run?->context, 'promotion_execution.plan.excluded', []))->pluck('excluded_reason')->all())
            ->toEqualCanonicalizing(['blocked', 'manual_mapping_required']);

    Queue::assertPushed(CrossEnvironmentPromotionExecutionJob::class, function (CrossEnvironmentPromotionExecutionJob $job) use ($run): bool {
        return $job->getOperationRun()?->is($run);
    });
});

it('does not queue a promotion run when the current preflight has no ready governed subjects', function (): void {
    Queue::fake();

    $fixture = $this->makeCrossEnvironmentCompareFixture();

    $blocked = $this->createPortfolioCompareSubject(
        tenant: $fixture['sourceEnvironment'],
        displayName: 'Blocked Policy',
        snapshot: ['settings' => [['key' => 'blocked', 'value' => 1]]],
    );
    $blocked['version']->delete();

    $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);

    Livewire::withQueryParams([
        'source_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
        'target_environment_id' => (int) $fixture['targetEnvironment']->getKey(),
        'policy_type' => ['deviceConfiguration'],
    ])
        ->actingAs($fixture['user'])
        ->test(CrossEnvironmentComparePage::class)
        ->call('generatePromotionPreflight')
        ->assertActionVisible('executePromotion')
        ->assertActionDisabled('executePromotion')
        ->assertActionExists('executePromotion', fn (Action $action): bool => $action->getTooltip() === 'Current promotion preflight has no ready governed subjects to execute.')
        ->call('executePromotion')
        ->assertNotified('Promotion execution unavailable');

    expect(OperationRun::query()->count())->toBe(0);

    Queue::assertNothingPushed();
});