<?php

declare(strict_types=1);

use App\Livewire\BaselineCompareEvidenceGapTable;
use App\Support\Badges\TagBadgeCatalog;
use App\Support\Badges\TagBadgeDomain;
use App\Support\Baselines\BaselineCompareEvidenceGapDetails;
use Filament\Tables\Table;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Features\SupportTesting\Testable;
use Livewire\Livewire;
use Tests\Feature\Baselines\Support\BaselineSubjectResolutionFixtures;

uses(RefreshDatabase::class);

function baselineCompareEvidenceGapTable(Testable $component): Table
{
    return $component->instance()->getTable();
}

/**
 * @return list<array<string, mixed>>
 */
function baselineCompareEvidenceGapBuckets(): array
{
    return BaselineCompareEvidenceGapDetails::fromContext(BaselineSubjectResolutionFixtures::compareContext([
        BaselineSubjectResolutionFixtures::structuredGap([
            'policy_type' => 'deviceConfiguration',
            'subject_key' => 'WiFi-Corp-Profile',
            'subject_class' => 'policy_backed',
            'resolution_path' => 'policy',
            'resolution_outcome' => 'ambiguous_match',
            'reason_code' => 'ambiguous_match',
            'operator_action_category' => 'inspect_subject_mapping',
        ]),
        BaselineSubjectResolutionFixtures::structuredGap([
            'policy_type' => 'deviceConfiguration',
            'subject_key' => 'VPN-Always-On',
            'subject_class' => 'policy_backed',
            'resolution_path' => 'policy',
            'resolution_outcome' => 'ambiguous_match',
            'reason_code' => 'ambiguous_match',
            'operator_action_category' => 'inspect_subject_mapping',
        ]),
        BaselineSubjectResolutionFixtures::structuredGap([
            'policy_type' => 'deviceCompliancePolicy',
            'subject_key' => 'Windows-Encryption-Required',
            'subject_class' => 'policy_backed',
            'resolution_path' => 'policy',
            'resolution_outcome' => 'ambiguous_match',
            'reason_code' => 'ambiguous_match',
            'operator_action_category' => 'inspect_subject_mapping',
        ]),
        BaselineSubjectResolutionFixtures::structuredGap([
            'policy_type' => 'deviceConfiguration',
            'subject_key' => 'Deleted-Policy-ABC',
            'resolution_outcome' => 'policy_record_missing',
            'reason_code' => 'policy_record_missing',
            'operator_action_category' => 'run_policy_sync_or_backup',
        ]),
        BaselineSubjectResolutionFixtures::structuredGap([
            'policy_type' => 'deviceCompliancePolicy',
            'subject_key' => 'Retired-Compliance-Policy',
            'resolution_outcome' => 'policy_record_missing',
            'reason_code' => 'policy_record_missing',
            'operator_action_category' => 'run_policy_sync_or_backup',
        ]),
    ]))['buckets'];
}

it('uses a Filament table for evidence-gap rows with searchable visible columns', function (): void {
    $component = Livewire::test(BaselineCompareEvidenceGapTable::class, [
        'buckets' => baselineCompareEvidenceGapBuckets(),
        'context' => 'canonical-run',
    ]);

    $table = baselineCompareEvidenceGapTable($component);

    expect($table->isSearchable())->toBeTrue();
    expect($table->getDefaultSortColumn())->toBe('reason_label');
    expect($table->getColumn('reason_label')?->isSearchable())->toBeTrue();
    expect($table->getColumn('governed_subject_label')?->isSearchable())->toBeTrue();
    expect($table->getColumn('subject_class_label')?->isSearchable())->toBeTrue();
    expect($table->getColumn('resolution_outcome_label')?->isSearchable())->toBeTrue();
    expect($table->getColumn('operator_action_category_label')?->isSearchable())->toBeTrue();
    expect($table->getColumn('subject_key')?->isSearchable())->toBeTrue();

    $component
        ->assertSee('WiFi-Corp-Profile')
        ->assertSee('Deleted-Policy-ABC')
        ->assertSee('Reason')
        ->assertSee('Governed subject')
        ->assertSee('Subject class')
        ->assertSee('Outcome')
        ->assertSee('Next action')
        ->assertSee('Subject key')
        ->assertSee('Policy-backed')
        ->assertSee('Policy record missing')
        ->assertSee('Run policy sync or backup')
        ->assertSee(TagBadgeCatalog::spec(TagBadgeDomain::PolicyType, 'deviceConfiguration')->label)
        ->assertSee(TagBadgeCatalog::spec(TagBadgeDomain::PolicyType, 'deviceCompliancePolicy')->label);
});

it('filters evidence-gap rows by table search and select filters', function (): void {
    Livewire::test(BaselineCompareEvidenceGapTable::class, [
        'buckets' => baselineCompareEvidenceGapBuckets(),
        'context' => 'tenant-landing',
    ])
        ->searchTable('Deleted-Policy-ABC')
        ->assertSee('Deleted-Policy-ABC')
        ->assertDontSee('WiFi-Corp-Profile');

    Livewire::test(BaselineCompareEvidenceGapTable::class, [
        'buckets' => baselineCompareEvidenceGapBuckets(),
        'context' => 'tenant-landing-filters',
    ])
        ->filterTable('reason_code', 'policy_record_missing')
        ->assertSee('Retired-Compliance-Policy')
        ->assertDontSee('VPN-Always-On')
        ->filterTable('policy_type', 'deviceCompliancePolicy')
        ->assertSee('Device Compliance')
        ->assertSee('Retired-Compliance-Policy')
        ->assertDontSee('Deleted-Policy-ABC')
        ->filterTable('operator_action_category', 'run_policy_sync_or_backup')
        ->assertSee('Run policy sync or backup')
        ->filterTable('subject_class', 'policy_backed')
        ->assertSee('Policy-backed');
});

it('shows an explicit empty state when only missing-detail buckets exist', function (): void {
    $buckets = BaselineCompareEvidenceGapDetails::fromContext([
        'baseline_compare' => [
            'evidence_gaps' => [
                'count' => 2,
                'by_reason' => [
                    'policy_record_missing' => 2,
                ],
                'subjects' => [],
            ],
        ],
    ])['buckets'];

    Livewire::test(BaselineCompareEvidenceGapTable::class, [
        'buckets' => $buckets,
        'context' => 'legacy-run',
    ])
        ->assertSee('No recorded gap rows match this view')
        ->assertSee('Adjust the current search or filters to review other affected subjects.');
});
