<?php

declare(strict_types=1);

use App\Support\OperationCatalog;
use App\Support\OperationRunType;

it('resolves legacy operation aliases to a canonical operator meaning', function (): void {
    $resolution = OperationCatalog::resolve('inventory_sync');

    expect($resolution->canonical->canonicalCode)->toBe('inventory.sync')
        ->and($resolution->canonical->displayLabel)->toBe('Inventory sync')
        ->and($resolution->aliasStatus)->toBe('legacy_alias')
        ->and($resolution->wasLegacyAlias)->toBeTrue()
        ->and(array_map(static fn ($alias): string => $alias->rawValue, $resolution->aliasesConsidered))
            ->toContain('inventory_sync', 'provider.inventory.sync');
});

it('resolves canonical backup set update values without treating them as legacy aliases', function (): void {
    $resolution = OperationCatalog::resolve('backup_set.update');

    expect($resolution->canonical->canonicalCode)->toBe('backup_set.update')
        ->and($resolution->canonical->displayLabel)->toBe('Backup set update')
        ->and($resolution->aliasStatus)->toBe('canonical')
        ->and($resolution->wasLegacyAlias)->toBeFalse()
        ->and(array_map(static fn ($alias): string => $alias->rawValue, $resolution->aliasesConsidered))
            ->toBe(['backup_set.update']);
});

it('deduplicates filter options by canonical operation code while preserving raw aliases for queries', function (): void {
    expect(OperationCatalog::filterOptions(['inventory_sync', 'provider.inventory.sync', 'policy.sync']))->toBe([
        'inventory.sync' => 'Inventory sync',
        'policy.sync' => 'Policy sync',
    ])->and(OperationCatalog::rawValuesForCanonical('inventory.sync'))
        ->toContain('inventory_sync', 'provider.inventory.sync')
        ->and(OperationCatalog::rawValuesForCanonical('backup_set.update'))
        ->toBe(['backup_set.update']);
});

it('maps enum-backed storage values to canonical operation codes', function (): void {
    expect(OperationRunType::BaselineCompare->canonicalCode())->toBe('baseline.compare')
        ->and(OperationRunType::DirectoryGroupsSync->canonicalCode())->toBe('directory.groups.sync')
    ->and(OperationRunType::BackupSetUpdate->canonicalCode())->toBe('backup_set.update');
});

it('keeps legacy aliases as read-side compatibility only', function (): void {
    $aliasInventory = OperationCatalog::aliasInventory();

    foreach ($aliasInventory as $rawValue => $metadata) {
        if (($metadata['alias_status'] ?? null) !== 'legacy_alias') {
            continue;
        }

        expect($metadata['write_allowed'] ?? null)
            ->toBeFalse("Legacy alias [{$rawValue}] must not be write-time truth.");
    }
});

it('keeps unknown operation values explicitly unknown', function (): void {
    $resolution = OperationCatalog::resolve('inventory-sync');

    expect($resolution->canonical->canonicalCode)->toBe('inventory-sync')
        ->and($resolution->canonical->displayLabel)->toBe('Unknown operation')
        ->and($resolution->aliasStatus)->toBe('unknown')
        ->and($resolution->wasLegacyAlias)->toBeFalse()
        ->and($resolution->aliasesConsidered)->toBe([]);
});

it('publishes contributor-facing operation inventories and alias retirement metadata', function (): void {
    $descriptor = OperationCatalog::ownershipDescriptor();
    $canonicalInventory = OperationCatalog::canonicalInventory();
    $aliasInventory = OperationCatalog::aliasInventory();

    expect($descriptor->registryKey)->toBe('operation_catalog')
        ->and($descriptor->boundaryClassification)->toBe('platform_core')
        ->and($canonicalInventory['baseline.compare']['display_label'] ?? null)->toBe('Baseline compare')
        ->and($aliasInventory['baseline_compare']['canonical_name'] ?? null)->toBe('baseline.compare')
        ->and($aliasInventory['baseline_compare']['retirement_path'] ?? null)->toContain('baseline.compare');
});
