<?php

declare (strict_types=1);
namespace PoPSchema\SchemaCommons\TypeResolvers\ScalarType;

use PoP\ComponentModel\Feedback\ObjectTypeFieldResolutionFeedback;
use PoP\ComponentModel\Feedback\ObjectTypeFieldResolutionFeedbackStore;
use PoP\ComponentModel\TypeResolvers\ScalarType\AbstractScalarTypeResolver;
use PoP\GraphQLParser\Spec\Parser\Ast\AstInterface;
use PoP\Root\App;
use PoP\ComponentModel\Feedback\FeedbackItemResolution;
use PoPSchema\SchemaCommons\FeedbackItemProviders\InputValueCoercionErrorFeedbackItemProvider;
use stdClass;
/**
 * This type is similar to Enum in that only values from a fixed-set
 * can be provided, but it is validated as a String.
 *
 * This is because Enum values have several constraints:
 *
 * - Can't have spaces
 * - Can't have special chars, such as `-`
 *
 * For whenever the option values may not satisfy these constraints,
 * this type can be used instead
 * @internal
 */
abstract class AbstractEnumStringScalarTypeResolver extends AbstractScalarTypeResolver implements \PoPSchema\SchemaCommons\TypeResolvers\ScalarType\EnumStringScalarTypeResolverInterface
{
    /** @var string[]|null */
    protected ?array $consolidatedPossibleValuesCache = null;
    public final const HOOK_POSSIBLE_VALUES = __CLASS__ . ':possible-values';
    public final const HOOK_BEFORE_POSSIBLE_VALUES = __CLASS__ . ':before-possible-values';
    public function coerceValue(string|int|float|bool|stdClass $inputValue, AstInterface $astNode, ObjectTypeFieldResolutionFeedbackStore $objectTypeFieldResolutionFeedbackStore) : string|int|float|bool|object|null
    {
        $errorCount = $objectTypeFieldResolutionFeedbackStore->getErrorCount();
        $this->validateIsNotStdClass($inputValue, $astNode, $objectTypeFieldResolutionFeedbackStore);
        if ($objectTypeFieldResolutionFeedbackStore->getErrorCount() > $errorCount) {
            return null;
        }
        /** @var string|int|float|bool $inputValue */
        $possibleValues = $this->getConsolidatedPossibleValues();
        if (!\in_array($inputValue, $possibleValues)) {
            $objectTypeFieldResolutionFeedbackStore->addError(new ObjectTypeFieldResolutionFeedback(new FeedbackItemResolution(InputValueCoercionErrorFeedbackItemProvider::class, InputValueCoercionErrorFeedbackItemProvider::E2, [$inputValue, $this->getMaybeNamespacedTypeName(), \implode($this->__('\', \''), $possibleValues)]), $astNode));
            return null;
        }
        return (string) $inputValue;
    }
    /**
     * Consolidation of the possible values. Call this function to read the data
     * instead of the individual functions, since it applies hooks to override/extend.
     *
     * @return string[]
     */
    public final function getConsolidatedPossibleValues() : array
    {
        if ($this->consolidatedPossibleValuesCache !== null) {
            return $this->consolidatedPossibleValuesCache;
        }
        /**
         * Allow to initialize the possible values
         */
        App::doAction(self::HOOK_BEFORE_POSSIBLE_VALUES, $this);
        /**
         * Allow to override/extend the enum values
         */
        $this->consolidatedPossibleValuesCache = App::applyFilters(self::HOOK_POSSIBLE_VALUES, $this->getPossibleValues(), $this) ?? [];
        if ($this->sortPossibleValues()) {
            \sort($this->consolidatedPossibleValuesCache);
        }
        return $this->consolidatedPossibleValuesCache;
    }
    public final function getTypeDescription() : string
    {
        $possibleValues = $this->getConsolidatedPossibleValues();
        $valueDescriptions = [];
        foreach ($possibleValues as $value) {
            $valueDesc = $this->getPossibleValueDescription($value);
            if ($valueDesc) {
                $valueDescriptions[] = \sprintf($this->__('`%s`: %s', 'gatographql'), $value, $valueDesc);
            } else {
                $valueDescriptions[] = \sprintf('`%s`', $value);
            }
        }
        $enumStringTypeDescription = $this->getEnumStringTypeDescription();
        // If there are no possible values, return the description + "No values available"
        if ($valueDescriptions === []) {
            $noValuesMessage = $this->__('No values available', 'gatographql');
            return $enumStringTypeDescription !== null ? \sprintf($this->__('%s. %s', 'gatographql'), $enumStringTypeDescription, $noValuesMessage) : $noValuesMessage;
        }
        $possibleValuesDescription = \sprintf($this->__('Possible values: %s.', 'gatographql'), \implode($this->__(', ', 'gatographql'), $valueDescriptions));
        return $enumStringTypeDescription !== null ? \sprintf($this->__('%s. %s', 'gatographql'), $enumStringTypeDescription, $possibleValuesDescription) : $possibleValuesDescription;
    }
    public function getEnumStringTypeDescription() : ?string
    {
        return null;
    }
    public function sortPossibleValues() : bool
    {
        return \true;
    }
    public function getPossibleValueDescription(string $possibleValue) : ?string
    {
        return null;
    }
}
