<?php

declare(strict_types=1);

namespace App\Support\Providers\Capabilities;

use App\Support\Providers\ProviderReasonCodes;
use InvalidArgumentException;

final class ProviderCapabilityRegistry
{
    /**
     * @return array<string, ProviderCapabilityDefinition>
     */
    public function definitions(): array
    {
        return [
            'provider_connection_check' => new ProviderCapabilityDefinition(
                key: 'provider_connection_check',
                label: 'Provider connection check',
                operationTypes: ['provider.connection.check'],
                providerRequirementKeys: ['permissions.admin_consent'],
                defaultReasonCode: ProviderReasonCodes::ProviderConsentMissing,
            ),
            'inventory_read' => new ProviderCapabilityDefinition(
                key: 'inventory_read',
                label: 'Inventory read',
                operationTypes: ['inventory.sync'],
                providerRequirementKeys: ['permissions.intune_configuration', 'permissions.intune_apps'],
                defaultReasonCode: ProviderReasonCodes::ProviderPermissionMissing,
            ),
            'configuration_read' => new ProviderCapabilityDefinition(
                key: 'configuration_read',
                label: 'Configuration read',
                operationTypes: ['compliance.snapshot'],
                providerRequirementKeys: ['permissions.intune_configuration'],
                defaultReasonCode: ProviderReasonCodes::ProviderPermissionMissing,
            ),
            'restore_execute' => new ProviderCapabilityDefinition(
                key: 'restore_execute',
                label: 'Restore execute',
                operationTypes: ['restore.execute'],
                providerRequirementKeys: ['permissions.intune_configuration', 'permissions.intune_rbac_assignments'],
                defaultReasonCode: ProviderReasonCodes::IntuneRbacPermissionMissing,
            ),
            'directory_groups_read' => new ProviderCapabilityDefinition(
                key: 'directory_groups_read',
                label: 'Directory groups read',
                operationTypes: ['directory.groups.sync'],
                providerRequirementKeys: ['permissions.directory_groups'],
                defaultReasonCode: ProviderReasonCodes::ProviderPermissionMissing,
            ),
            'directory_role_definitions_read' => new ProviderCapabilityDefinition(
                key: 'directory_role_definitions_read',
                label: 'Directory role definitions read',
                operationTypes: ['directory.role_definitions.sync'],
                providerRequirementKeys: ['provider.directory_role_definitions', 'permissions.admin_consent'],
                defaultReasonCode: ProviderReasonCodes::ProviderPermissionMissing,
            ),
        ];
    }

    /**
     * @return array<string, ProviderCapabilityDefinition>
     */
    public function all(): array
    {
        return $this->definitions();
    }

    /**
     * @return array<int, string>
     */
    public function keys(): array
    {
        return array_keys($this->definitions());
    }

    public function get(string $key): ProviderCapabilityDefinition
    {
        $key = trim($key);
        $definition = $this->definitions()[$key] ?? null;

        if (! $definition instanceof ProviderCapabilityDefinition) {
            throw new InvalidArgumentException("Unknown provider capability key: {$key}");
        }

        return $definition;
    }

    /**
     * @return array<int, ProviderCapabilityDefinition>
     */
    public function forOperationType(string $operationType): array
    {
        $operationType = trim($operationType);

        return array_values(array_filter(
            $this->definitions(),
            static fn (ProviderCapabilityDefinition $definition): bool => in_array($operationType, $definition->operationTypes, true),
        ));
    }

    /**
     * @return array<int, string>
     */
    public function keysForOperationType(string $operationType): array
    {
        return array_map(
            static fn (ProviderCapabilityDefinition $definition): string => $definition->key,
            $this->forOperationType($operationType),
        );
    }
}
