<?php

declare(strict_types=1);

namespace App\Support\Operations;

final readonly class QueuedExecutionLegitimacyDecision
{
    /**
     * @param  array{identity_type:string,user_id:int|null}|null  $initiator
     * @param  array{workspace_id:int,managed_environment_id:int|null,provider_connection_id:int|null}  $targetScope
     * @param  array{workspace_scope:string,tenant_scope:string,capability:string,tenant_operability:string,execution_prerequisites:string}  $checks
     * @param  array<string, mixed>  $metadata
     */
    public function __construct(
        public string $operationType,
        public bool $allowed,
        public ExecutionAuthorityMode $authorityMode,
        public ?array $initiator,
        public array $targetScope,
        public array $checks,
        public ?ExecutionDenialClass $denialClass = null,
        public ?ExecutionDenialReasonCode $reasonCode = null,
        public bool $retryable = false,
        public array $metadata = [],
    ) {}

    /**
     * @param  array{workspace_scope:string,tenant_scope:string,capability:string,tenant_operability:string,execution_prerequisites:string}  $checks
     * @param  array<string, mixed>  $metadata
     */
    public static function allow(QueuedExecutionContext $context, array $checks, array $metadata = []): self
    {
        return new self(
            operationType: $context->operationType,
            allowed: true,
            authorityMode: $context->authorityMode,
            initiator: $context->initiatorSnapshot(),
            targetScope: $context->targetScope,
            checks: $checks,
            metadata: $metadata,
        );
    }

    /**
     * @param  array{workspace_scope:string,tenant_scope:string,capability:string,tenant_operability:string,execution_prerequisites:string}  $checks
     * @param  array<string, mixed>  $metadata
     */
    public static function deny(
        QueuedExecutionContext $context,
        array $checks,
        ExecutionDenialReasonCode $reasonCode,
        array $metadata = [],
    ): self {
        $denialClass = $reasonCode->denialClass();

        return new self(
            operationType: $context->operationType,
            allowed: false,
            authorityMode: $context->authorityMode,
            initiator: $context->initiatorSnapshot(),
            targetScope: $context->targetScope,
            checks: $checks,
            denialClass: $denialClass,
            reasonCode: $reasonCode,
            retryable: $denialClass->isRetryable(),
            metadata: $metadata,
        );
    }

    /**
     * @return array{workspace_scope:string,tenant_scope:string,capability:string,tenant_operability:string,execution_prerequisites:string}
     */
    public static function defaultChecks(): array
    {
        return [
            'workspace_scope' => 'not_applicable',
            'tenant_scope' => 'not_applicable',
            'capability' => 'not_applicable',
            'tenant_operability' => 'not_applicable',
            'execution_prerequisites' => 'not_applicable',
        ];
    }

    /**
     * @return array<string, mixed>
     */
    public function toArray(): array
    {
        return [
            'operation_type' => $this->operationType,
            'authority_mode' => $this->authorityMode->value,
            'allowed' => $this->allowed,
            'retryable' => $this->retryable,
            'reason_code' => $this->reasonCode?->value,
            'denial_class' => $this->denialClass?->value,
            'initiator' => $this->initiator,
            'target_scope' => $this->targetScope,
            'checks' => $this->checks,
            'metadata' => $this->metadata,
        ];
    }
}
