<?php

declare (strict_types=1);
namespace OCA\Talk\Vendor\CuyZ\Valinor\Mapper\Tree\Message;

use OCA\Talk\Vendor\CuyZ\Valinor\Utility\String\StringFormatter;
use Stringable;
use Throwable;
use function array_merge;
/** @api */
final class NodeMessage implements Message, HasCode, Stringable
{
    /** @var array<string, string> */
    private array $parameters = [];
    private string $locale = StringFormatter::DEFAULT_LOCALE;
    /**
     * @internal
     */
    public function __construct(private Message $message, private string $body, private string $name, private string $path, private string $type, private string $expectedSignature, private string $sourceValue)
    {
    }
    /** @pure */
    public function withLocale(string $locale): self
    {
        $clone = clone $this;
        $clone->locale = $locale;
        return $clone;
    }
    /** @pure */
    public function locale(): string
    {
        return $this->locale;
    }
    /**
     * Allows to customize the body of the message. It can contain placeholders
     * that will be replaced by their corresponding values, as described below:
     *
     * | Placeholder            | Description                                  |
     * |------------------------|----------------------------------------------|
     * | `{message_code}`       | The code of the message                      |
     * | `{node_name}`          | Name of the node                             |
     * | `{node_path}`          | Path of the node                             |
     * | `{node_type}`          | PHP type of the node                         |
     * | `{expected_signature}` | String representation of the expected type   |
     * | `{source_value}`       | The source value that was given to the node  |
     * | `{original_message}`   | The original message before being customized |
     *
     * Example:
     *
     * ```
     * $message = $message->withBody('new message for value: {source_value}');
     * ```
     *
     * @pure
     */
    public function withBody(string $body): self
    {
        $clone = clone $this;
        $clone->body = $body;
        return $clone;
    }
    /** @pure */
    public function body(): string
    {
        return $this->body;
    }
    /** @pure */
    public function name(): string
    {
        return $this->name;
    }
    /** @pure */
    public function path(): string
    {
        return $this->path;
    }
    /** @pure */
    public function type(): string
    {
        return $this->type;
    }
    /** @pure */
    public function expectedSignature(): string
    {
        return $this->expectedSignature;
    }
    /** @pure */
    public function sourceValue(): string
    {
        return $this->sourceValue;
    }
    /**
     * Adds a parameter that can replace a placeholder in the message body.
     *
     * @see self::withBody()
     *
     * @pure
     */
    public function withParameter(string $name, string $value): self
    {
        $clone = clone $this;
        $clone->parameters[$name] = $value;
        return $clone;
    }
    /** @pure */
    public function originalMessage(): Message
    {
        return $this->message;
    }
    /** @pure */
    public function isError(): bool
    {
        return $this->message instanceof ErrorMessage;
    }
    /** @pure */
    public function code(): string
    {
        if ($this->message instanceof HasCode) {
            return $this->message->code();
        }
        if ($this->message instanceof Throwable) {
            return (string) $this->message->getCode();
        }
        return 'unknown';
    }
    /** @pure */
    public function toString(): string
    {
        return $this->format($this->body, $this->parameters());
    }
    /** @pure */
    public function __toString(): string
    {
        return $this->toString();
    }
    /**
     * @pure
     * @param array<string, string> $parameters
     */
    private function format(string $body, array $parameters): string
    {
        return StringFormatter::format($this->locale, $body, $parameters);
    }
    /**
     * @return array<string, string>
     */
    private function parameters(): array
    {
        $parameters = ['message_code' => $this->code(), 'node_name' => $this->name, 'node_path' => $this->path, 'node_type' => $this->type, 'expected_signature' => $this->expectedSignature, 'source_value' => $this->sourceValue];
        if ($this->message instanceof HasParameters) {
            $parameters += $this->message->parameters();
        }
        $parameters['original_message'] = $this->format($this->message->body(), $parameters);
        return array_merge($parameters, $this->parameters);
    }
}