<?php

declare(strict_types=1);

namespace App\Support\Governance\Controls;

final readonly class CanonicalControlResolver
{
    /**
     * @var list<string>
     */
    private const SUPPORTED_CONTEXTS = ['baseline', 'drift', 'finding', 'evidence', 'exception', 'review', 'report'];

    public function __construct(
        private CanonicalControlCatalog $catalog,
    ) {}

    public function resolve(CanonicalControlResolutionRequest $request): CanonicalControlResolutionResult
    {
        if ($request->provider !== 'microsoft') {
            return CanonicalControlResolutionResult::unresolved('unsupported_provider', $request);
        }

        if (! in_array($request->consumerContext, self::SUPPORTED_CONTEXTS, true)) {
            return CanonicalControlResolutionResult::unresolved('unsupported_consumer_context', $request);
        }

        if (! $request->hasDiscriminator()) {
            return CanonicalControlResolutionResult::unresolved('insufficient_context', $request);
        }

        $bindings = array_values(array_filter(
            $this->catalog->microsoftBindings(),
            static fn (MicrosoftSubjectBinding $binding): bool => $binding->matches($request),
        ));

        if ($bindings === []) {
            return CanonicalControlResolutionResult::unresolved('missing_binding', $request);
        }

        $primaryBindings = array_values(array_filter(
            $bindings,
            static fn (MicrosoftSubjectBinding $binding): bool => $binding->primary,
        ));

        if ($primaryBindings !== []) {
            $bindings = $primaryBindings;
        }

        $candidateControlKeys = array_values(array_unique(array_map(
            static fn (MicrosoftSubjectBinding $binding): string => $binding->controlKey,
            $bindings,
        )));

        sort($candidateControlKeys, SORT_STRING);

        if (count($candidateControlKeys) !== 1) {
            return CanonicalControlResolutionResult::ambiguous($candidateControlKeys, $request);
        }

        $definition = $this->catalog->find($candidateControlKeys[0]);

        if (! $definition instanceof CanonicalControlDefinition) {
            return CanonicalControlResolutionResult::unresolved('missing_binding', $request);
        }

        return CanonicalControlResolutionResult::resolved($definition);
    }
}
