<?php

declare(strict_types=1);

namespace Plugin\tnt_mcp\src\Mcp\Action;

/**
 * One `$_POST` key a controller reads, described well enough that an argument can be bound to it
 * without anyone re-reading the controller. Three things here are not derivable from the shop and
 * are the reason this class exists at all: `const` fields (the hidden switches such as
 * `neueVersandart=1` that decide which branch a controller takes), array fields whose name ends in
 * `[]`, and templated names such as `fAufpreis_{kZahlungsart}` that are expanded once per value of
 * the enum named by {@see self::$template}.
 */
final class FieldSpec
{
    private function __construct(
        public readonly string $name,
        public readonly string $type,
        public readonly bool $required,
        public readonly ?string $value,
        public readonly ?string $doc,
        public readonly ?EnumSpec $enum,
        public readonly ?string $template,
    ) {
    }

    /**
     * @param array<mixed> $raw
     */
    public static function fromArray(array $raw): self
    {
        $enum = $raw['enum'] ?? null;

        return new self(
            \is_string($raw['name'] ?? null) ? $raw['name'] : '',
            \is_string($raw['type'] ?? null) ? $raw['type'] : '',
            (bool)($raw['required'] ?? false),
            \is_string($raw['value'] ?? null) ? $raw['value'] : null,
            \is_string($raw['doc'] ?? null) ? $raw['doc'] : null,
            \is_array($enum) ? EnumSpec::fromArray($enum) : null,
            \is_string($raw['template'] ?? null) ? $raw['template'] : null,
        );
    }

    /** The argument name this field binds to, with `[]` and any `{…}` segment removed. */
    public function argumentName(): string
    {
        return Placeholder::baseName($this->name);
    }

    public function isArray(): bool
    {
        return \str_ends_with($this->name, '[]');
    }

    public function isTemplated(): bool
    {
        return $this->template !== null;
    }

    public function isConstant(): bool
    {
        return $this->type === 'const';
    }
}
