<?php

declare(strict_types=1);

namespace Anthropic\Messages;

use Anthropic\Core\Attributes\Api;
use Anthropic\Core\Concerns\SdkModel;
use Anthropic\Core\Contracts\BaseModel;

/**
 * @phpstan-type message_alias = array{
 *   id: string,
 *   content: list<TextBlock|ThinkingBlock|RedactedThinkingBlock|ToolUseBlock|ServerToolUseBlock|WebSearchToolResultBlock>,
 *   model: Model::*|string,
 *   role: string,
 *   stopReason: StopReason::*,
 *   stopSequence: string|null,
 *   type: string,
 *   usage: Usage,
 * }
 */
final class Message implements BaseModel
{
    /** @use SdkModel<message_alias> */
    use SdkModel;

    /**
     * Conversational role of the generated message.
     *
     * This will always be `"assistant"`.
     */
    #[Api]
    public string $role = 'assistant';

    /**
     * Object type.
     *
     * For Messages, this is always `"message"`.
     */
    #[Api]
    public string $type = 'message';

    /**
     * Unique object identifier.
     *
     * The format and length of IDs may change over time.
     */
    #[Api]
    public string $id;

    /**
     * Content generated by the model.
     *
     * This is an array of content blocks, each of which has a `type` that determines its shape.
     *
     * Example:
     *
     * ```json
     * [{"type": "text", "text": "Hi, I'm Claude."}]
     * ```
     *
     * If the request input `messages` ended with an `assistant` turn, then the response `content` will continue directly from that last turn. You can use this to constrain the model's output.
     *
     * For example, if the input `messages` were:
     * ```json
     * [
     *   {"role": "user", "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"},
     *   {"role": "assistant", "content": "The best answer is ("}
     * ]
     * ```
     *
     * Then the response `content` might be:
     *
     * ```json
     * [{"type": "text", "text": "B)"}]
     * ```
     *
     * @var list<TextBlock|ThinkingBlock|RedactedThinkingBlock|ToolUseBlock|ServerToolUseBlock|WebSearchToolResultBlock> $content
     */
    #[Api(list: ContentBlock::class)]
    public array $content;

    /**
     * The model that will complete your prompt.\n\nSee [models](https://docs.anthropic.com/en/docs/models-overview) for additional details and options.
     *
     * @var Model::*|string $model
     */
    #[Api(union: Model::class)]
    public string $model;

    /**
     * The reason that we stopped.
     *
     * This may be one the following values:
     * * `"end_turn"`: the model reached a natural stopping point
     * * `"max_tokens"`: we exceeded the requested `max_tokens` or the model's maximum
     * * `"stop_sequence"`: one of your provided custom `stop_sequences` was generated
     * * `"tool_use"`: the model invoked one or more tools
     * * `"pause_turn"`: we paused a long-running turn. You may provide the response back as-is in a subsequent request to let the model continue.
     * * `"refusal"`: when streaming classifiers intervene to handle potential policy violations
     *
     * In non-streaming mode this value is always non-null. In streaming mode, it is null in the `message_start` event and non-null otherwise.
     *
     * @var StopReason::* $stopReason
     */
    #[Api('stop_reason', enum: StopReason::class)]
    public string $stopReason;

    /**
     * Which custom stop sequence was generated, if any.
     *
     * This value will be a non-null string if one of your custom stop sequences was generated.
     */
    #[Api('stop_sequence')]
    public ?string $stopSequence;

    /**
     * Billing and rate-limit usage.
     *
     * Anthropic's API bills and rate-limits by token counts, as tokens represent the underlying cost to our systems.
     *
     * Under the hood, the API transforms requests into a format suitable for the model. The model's output then goes through a parsing stage before becoming an API response. As a result, the token counts in `usage` will not match one-to-one with the exact visible content of an API request or response.
     *
     * For example, `output_tokens` will be non-zero, even for an empty string response from Claude.
     *
     * Total input tokens in a request is the summation of `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`.
     */
    #[Api]
    public Usage $usage;

    /**
     * `new Message()` is missing required properties by the API.
     *
     * To enforce required parameters use
     * ```
     * Message::with(
     *   id: ...,
     *   content: ...,
     *   model: ...,
     *   stopReason: ...,
     *   stopSequence: ...,
     *   usage: ...,
     * )
     * ```
     *
     * Otherwise ensure the following setters are called
     *
     * ```
     * (new Message)
     *   ->withID(...)
     *   ->withContent(...)
     *   ->withModel(...)
     *   ->withStopReason(...)
     *   ->withStopSequence(...)
     *   ->withUsage(...)
     * ```
     */
    public function __construct()
    {
        $this->initialize();
    }

    /**
     * Construct an instance from the required parameters.
     *
     * You must use named parameters to construct any parameters with a default value.
     *
     * @param list<TextBlock|ThinkingBlock|RedactedThinkingBlock|ToolUseBlock|ServerToolUseBlock|WebSearchToolResultBlock> $content
     * @param Model::*|string $model
     * @param StopReason::* $stopReason
     */
    public static function with(
        string $id,
        array $content,
        string $model,
        string $stopReason,
        ?string $stopSequence,
        Usage $usage,
    ): self {
        $obj = new self;

        $obj->id = $id;
        $obj->content = $content;
        $obj->model = $model;
        $obj->stopReason = $stopReason;
        $obj->stopSequence = $stopSequence;
        $obj->usage = $usage;

        return $obj;
    }

    /**
     * Unique object identifier.
     *
     * The format and length of IDs may change over time.
     */
    public function withID(string $id): self
    {
        $obj = clone $this;
        $obj->id = $id;

        return $obj;
    }

    /**
     * Content generated by the model.
     *
     * This is an array of content blocks, each of which has a `type` that determines its shape.
     *
     * Example:
     *
     * ```json
     * [{"type": "text", "text": "Hi, I'm Claude."}]
     * ```
     *
     * If the request input `messages` ended with an `assistant` turn, then the response `content` will continue directly from that last turn. You can use this to constrain the model's output.
     *
     * For example, if the input `messages` were:
     * ```json
     * [
     *   {"role": "user", "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"},
     *   {"role": "assistant", "content": "The best answer is ("}
     * ]
     * ```
     *
     * Then the response `content` might be:
     *
     * ```json
     * [{"type": "text", "text": "B)"}]
     * ```
     *
     * @param list<TextBlock|ThinkingBlock|RedactedThinkingBlock|ToolUseBlock|ServerToolUseBlock|WebSearchToolResultBlock> $content
     */
    public function withContent(array $content): self
    {
        $obj = clone $this;
        $obj->content = $content;

        return $obj;
    }

    /**
     * The model that will complete your prompt.\n\nSee [models](https://docs.anthropic.com/en/docs/models-overview) for additional details and options.
     *
     * @param Model::*|string $model
     */
    public function withModel(string $model): self
    {
        $obj = clone $this;
        $obj->model = $model;

        return $obj;
    }

    /**
     * The reason that we stopped.
     *
     * This may be one the following values:
     * * `"end_turn"`: the model reached a natural stopping point
     * * `"max_tokens"`: we exceeded the requested `max_tokens` or the model's maximum
     * * `"stop_sequence"`: one of your provided custom `stop_sequences` was generated
     * * `"tool_use"`: the model invoked one or more tools
     * * `"pause_turn"`: we paused a long-running turn. You may provide the response back as-is in a subsequent request to let the model continue.
     * * `"refusal"`: when streaming classifiers intervene to handle potential policy violations
     *
     * In non-streaming mode this value is always non-null. In streaming mode, it is null in the `message_start` event and non-null otherwise.
     *
     * @param StopReason::* $stopReason
     */
    public function withStopReason(string $stopReason): self
    {
        $obj = clone $this;
        $obj->stopReason = $stopReason;

        return $obj;
    }

    /**
     * Which custom stop sequence was generated, if any.
     *
     * This value will be a non-null string if one of your custom stop sequences was generated.
     */
    public function withStopSequence(?string $stopSequence): self
    {
        $obj = clone $this;
        $obj->stopSequence = $stopSequence;

        return $obj;
    }

    /**
     * Billing and rate-limit usage.
     *
     * Anthropic's API bills and rate-limits by token counts, as tokens represent the underlying cost to our systems.
     *
     * Under the hood, the API transforms requests into a format suitable for the model. The model's output then goes through a parsing stage before becoming an API response. As a result, the token counts in `usage` will not match one-to-one with the exact visible content of an API request or response.
     *
     * For example, `output_tokens` will be non-zero, even for an empty string response from Claude.
     *
     * Total input tokens in a request is the summation of `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`.
     */
    public function withUsage(Usage $usage): self
    {
        $obj = clone $this;
        $obj->usage = $usage;

        return $obj;
    }
}
