import { deepCopy, omitUndefined } from './json.js';
import { ImageBlock, VideoBlock, DocumentBlock, encodeBase64, decodeBase64 } from './media.js';
import { CitationsBlock } from './citations.js';
/**
 * A message in a conversation between user and assistant.
 * Each message has a role (user or assistant) and an array of content blocks.
 */
export class Message {
    /**
     * Discriminator for message type.
     */
    type = 'message';
    /**
     * The role of the message sender.
     */
    role;
    /**
     * Array of content blocks that make up this message.
     */
    content;
    /**
     * Optional metadata, not sent to model providers.
     */
    metadata;
    constructor(data) {
        this.role = data.role;
        this.content = data.content;
        if (data.metadata !== undefined) {
            this.metadata = data.metadata;
        }
    }
    /**
     * Creates a Message instance from MessageData.
     */
    static fromMessageData(data) {
        const contentBlocks = data.content.map(contentBlockFromData);
        return new Message({
            role: data.role,
            content: contentBlocks,
            ...(data.metadata !== undefined && { metadata: data.metadata }),
        });
    }
    /**
     * Serializes the Message to a JSON-compatible MessageData object.
     * Called automatically by JSON.stringify().
     */
    toJSON() {
        return {
            role: this.role,
            content: this.content.map((block) => block.toJSON()),
            ...(this.metadata !== undefined && { metadata: this.metadata }),
        };
    }
    /**
     * Creates a Message instance from MessageData.
     * Alias for fromMessageData for API consistency.
     *
     * @param data - MessageData to deserialize
     * @returns Message instance
     */
    static fromJSON(data) {
        return Message.fromMessageData(data);
    }
    /**
     * Creates a deep copy of this Message (round-trips through serialization).
     */
    clone() {
        return Message.fromMessageData(deepCopy(this.toJSON()));
    }
}
/**
 * Text content block within a message.
 */
export class TextBlock {
    /**
     * Discriminator for text content.
     */
    type = 'textBlock';
    /**
     * Plain text content.
     */
    text;
    constructor(data) {
        this.text = data;
    }
    /**
     * Serializes the TextBlock to a JSON-compatible TextBlockData object.
     * Called automatically by JSON.stringify().
     */
    toJSON() {
        return { text: this.text };
    }
    /**
     * Creates a TextBlock instance from TextBlockData.
     *
     * @param data - TextBlockData to deserialize
     * @returns TextBlock instance
     */
    static fromJSON(data) {
        return new TextBlock(data.text);
    }
}
/**
 * Tool use content block.
 */
export class ToolUseBlock {
    /**
     * Discriminator for tool use content.
     */
    type = 'toolUseBlock';
    /**
     * The name of the tool to execute.
     */
    name;
    /**
     * Unique identifier for this tool use instance.
     */
    toolUseId;
    /**
     * The input parameters for the tool.
     * This can be any JSON-serializable value.
     */
    input;
    /**
     * Reasoning signature from thinking models (e.g., Gemini).
     * Must be preserved and sent back to the model for multi-turn tool use.
     */
    reasoningSignature;
    constructor(data) {
        this.name = data.name;
        this.toolUseId = data.toolUseId;
        this.input = data.input;
        if (data.reasoningSignature !== undefined) {
            this.reasoningSignature = data.reasoningSignature;
        }
    }
    /**
     * Serializes the ToolUseBlock to a JSON-compatible ContentBlockData object.
     * Called automatically by JSON.stringify().
     */
    toJSON() {
        return {
            toolUse: omitUndefined({
                name: this.name,
                toolUseId: this.toolUseId,
                input: this.input,
                reasoningSignature: this.reasoningSignature,
            }),
        };
    }
    /**
     * Creates a ToolUseBlock instance from its wrapped data format.
     *
     * @param data - Wrapped ToolUseBlockData to deserialize
     * @returns ToolUseBlock instance
     */
    static fromJSON(data) {
        return new ToolUseBlock(data.toolUse);
    }
}
/**
 * Tool result content block.
 */
export class ToolResultBlock {
    /**
     * Discriminator for tool result content.
     */
    type = 'toolResultBlock';
    /**
     * The ID of the tool use that this result corresponds to.
     */
    toolUseId;
    /**
     * Status of the tool execution.
     */
    status;
    /**
     * The content returned by the tool.
     */
    content;
    /**
     * The original error object when status is 'error'.
     * Available for inspection by hooks, error handlers, and agent loop.
     * Tools must wrap non-Error thrown values into Error objects.
     */
    error;
    constructor(data) {
        this.toolUseId = data.toolUseId;
        this.status = data.status;
        this.content = data.content;
        if (data.error !== undefined) {
            this.error = data.error;
        }
    }
    /**
     * Serializes the ToolResultBlock to a JSON-compatible ContentBlockData object.
     * Called automatically by JSON.stringify().
     * Note: The error field is not serialized (deferred for future implementation).
     */
    toJSON() {
        return {
            toolResult: {
                toolUseId: this.toolUseId,
                status: this.status,
                content: this.content.map((block) => block.toJSON()),
            },
        };
    }
    /**
     * Creates a ToolResultBlock instance from its wrapped data format.
     *
     * @param data - Wrapped ToolResultBlockData to deserialize
     * @returns ToolResultBlock instance
     */
    static fromJSON(data) {
        const content = data.toolResult.content.map(toolResultContentFromData);
        return new ToolResultBlock({
            toolUseId: data.toolResult.toolUseId,
            status: data.toolResult.status,
            content,
        });
    }
}
/**
 * Converts a single ToolResultContentData to a ToolResultContent class instance.
 *
 * @param data - The tool result content data to convert
 * @returns A ToolResultContent instance of the appropriate type
 * @throws Error if the content data type is unknown
 */
export function toolResultContentFromData(data) {
    if ('text' in data)
        return new TextBlock(data.text);
    if ('json' in data)
        return new JsonBlock(data);
    if ('image' in data)
        return ImageBlock.fromJSON(data);
    if ('video' in data)
        return VideoBlock.fromJSON(data);
    if ('document' in data)
        return DocumentBlock.fromJSON(data);
    throw new Error('Unknown ToolResultContentData type');
}
/**
 * Reasoning content block within a message.
 */
export class ReasoningBlock {
    /**
     * Discriminator for reasoning content.
     */
    type = 'reasoningBlock';
    /**
     * The text content of the reasoning process.
     */
    text;
    /**
     * A cryptographic signature for verification purposes.
     */
    signature;
    /**
     * The redacted content of the reasoning process.
     */
    redactedContent;
    constructor(data) {
        if (data.text !== undefined) {
            this.text = data.text;
        }
        if (data.signature !== undefined) {
            this.signature = data.signature;
        }
        if (data.redactedContent !== undefined) {
            this.redactedContent = data.redactedContent;
        }
    }
    /**
     * Serializes the ReasoningBlock to a JSON-compatible ContentBlockData object.
     * Called automatically by JSON.stringify().
     * Uint8Array redactedContent is encoded as base64 string.
     */
    toJSON() {
        return {
            reasoning: omitUndefined({
                text: this.text,
                signature: this.signature,
                redactedContent: this.redactedContent ? encodeBase64(this.redactedContent) : undefined,
            }),
        };
    }
    /**
     * Creates a ReasoningBlock instance from its wrapped data format.
     * Base64-encoded redactedContent is decoded back to Uint8Array.
     *
     * @param data - Wrapped ReasoningBlockData to deserialize (accepts both string and Uint8Array for redactedContent)
     * @returns ReasoningBlock instance
     */
    static fromJSON(data) {
        const reasoning = data.reasoning;
        const result = {};
        if (reasoning.text !== undefined) {
            result.text = reasoning.text;
        }
        if (reasoning.signature !== undefined) {
            result.signature = reasoning.signature;
        }
        if (reasoning.redactedContent !== undefined) {
            result.redactedContent =
                typeof reasoning.redactedContent === 'string'
                    ? decodeBase64(reasoning.redactedContent)
                    : reasoning.redactedContent;
        }
        return new ReasoningBlock(result);
    }
}
/**
 * Cache point block for prompt caching.
 * Marks a position in a message or system prompt where caching should occur.
 */
export class CachePointBlock {
    /**
     * Discriminator for cache point.
     */
    type = 'cachePointBlock';
    /**
     * The cache type. Currently only 'default' is supported.
     */
    cacheType;
    /**
     * Optional TTL for the cache entry. See {@link CachePointBlockData.ttl} for the
     * provider-specific value space.
     */
    ttl;
    constructor(data) {
        this.cacheType = data.cacheType;
        if (data.ttl !== undefined) {
            this.ttl = data.ttl;
        }
    }
    /**
     * Serializes the CachePointBlock to a JSON-compatible ContentBlockData object.
     * Called automatically by JSON.stringify().
     */
    toJSON() {
        return {
            cachePoint: {
                cacheType: this.cacheType,
                ...(this.ttl !== undefined && { ttl: this.ttl }),
            },
        };
    }
    /**
     * Creates a CachePointBlock instance from its wrapped data format.
     *
     * @param data - Wrapped CachePointBlockData to deserialize
     * @returns CachePointBlock instance
     */
    static fromJSON(data) {
        return new CachePointBlock(data.cachePoint);
    }
}
/**
 * JSON content block within a message.
 * Used for structured data returned from tools or model responses.
 */
export class JsonBlock {
    /**
     * Discriminator for JSON content.
     */
    type = 'jsonBlock';
    /**
     * Structured JSON data.
     */
    json;
    constructor(data) {
        this.json = data.json;
    }
    /**
     * Serializes the JsonBlock to a JSON-compatible JsonBlockData object.
     * Called automatically by JSON.stringify().
     */
    toJSON() {
        return { json: this.json };
    }
    /**
     * Creates a JsonBlock instance from JsonBlockData.
     *
     * @param data - JsonBlockData to deserialize
     * @returns JsonBlock instance
     */
    static fromJSON(data) {
        return new JsonBlock(data);
    }
}
/**
 * Converts SystemPromptData to SystemPrompt by converting data blocks to class instances.
 * If already in SystemPrompt format (class instances), returns as-is.
 *
 * @param data - System prompt data to convert
 * @returns SystemPrompt with class-based content blocks
 */
export function systemPromptFromData(data) {
    if (typeof data === 'string') {
        return data;
    }
    // Convert data format to class instances
    return data.map((block) => {
        if ('type' in block) {
            return block;
        }
        else if ('cachePoint' in block) {
            return new CachePointBlock(block.cachePoint);
        }
        else if ('guardContent' in block) {
            return new GuardContentBlock(block.guardContent);
        }
        else if ('text' in block) {
            return new TextBlock(block.text);
        }
        else {
            throw new Error('Unknown SystemContentBlockData type');
        }
    });
}
/**
 * Converts a SystemPrompt to its data representation for serialization.
 *
 * @param prompt - System prompt to convert (string or content block array)
 * @returns SystemPromptData suitable for JSON serialization
 */
export function systemPromptToData(prompt) {
    if (typeof prompt === 'string') {
        return prompt;
    }
    // Convert content blocks to their data representation
    return prompt.map((block) => block.toJSON());
}
/**
 * Creates a deep copy of a SystemPrompt by round-tripping through serialization.
 */
export function cloneSystemPrompt(prompt) {
    return systemPromptFromData(systemPromptToData(prompt));
}
/**
 * Guard content block for guardrail evaluation.
 * Marks content that should be evaluated by guardrails for safety, grounding, or other policies.
 * Can be used in both message content and system prompts.
 */
export class GuardContentBlock {
    /**
     * Discriminator for guard content.
     */
    type = 'guardContentBlock';
    /**
     * Text content with evaluation qualifiers.
     */
    text;
    /**
     * Image content with evaluation qualifiers.
     */
    image;
    constructor(data) {
        if (!data.text && !data.image) {
            throw new Error('GuardContentBlock must have either text or image content');
        }
        if (data.text && data.image) {
            throw new Error('GuardContentBlock cannot have both text and image content');
        }
        if (data.text) {
            this.text = data.text;
        }
        if (data.image) {
            this.image = data.image;
        }
    }
    /**
     * Serializes the GuardContentBlock to a JSON-compatible ContentBlockData object.
     * Called automatically by JSON.stringify().
     * Uint8Array image bytes are encoded as base64 string.
     */
    toJSON() {
        const data = {};
        if (this.text) {
            data.text = this.text;
        }
        if (this.image) {
            data.image = {
                format: this.image.format,
                source: { bytes: encodeBase64(this.image.source.bytes) },
            };
        }
        return { guardContent: data };
    }
    /**
     * Creates a GuardContentBlock instance from its wrapped data format.
     * Base64-encoded image bytes are decoded back to Uint8Array.
     *
     * @param data - Wrapped GuardContentBlockData to deserialize (accepts both string and Uint8Array for image bytes)
     * @returns GuardContentBlock instance
     */
    static fromJSON(data) {
        const guardContent = data.guardContent;
        const result = {};
        if (guardContent.text) {
            result.text = guardContent.text;
        }
        if (guardContent.image) {
            const bytes = guardContent.image.source.bytes;
            result.image = {
                format: guardContent.image.format,
                source: {
                    bytes: typeof bytes === 'string' ? decodeBase64(bytes) : bytes,
                },
            };
        }
        return new GuardContentBlock(result);
    }
}
/**
 * Converts ContentBlockData to a ContentBlock instance.
 * Handles all content block types including text, tool use/result, reasoning, cache points, guard content, and media blocks.
 *
 * @param data - The content block data to convert
 * @returns A ContentBlock instance of the appropriate type
 * @throws Error if the content block type is unknown
 */
export function contentBlockFromData(data) {
    if ('text' in data) {
        return new TextBlock(data.text);
    }
    else if ('toolUse' in data) {
        return new ToolUseBlock(data.toolUse);
    }
    else if ('toolResult' in data) {
        return ToolResultBlock.fromJSON(data);
    }
    else if ('reasoning' in data) {
        return ReasoningBlock.fromJSON(data);
    }
    else if ('cachePoint' in data) {
        return CachePointBlock.fromJSON(data);
    }
    else if ('guardContent' in data) {
        return GuardContentBlock.fromJSON(data);
    }
    else if ('image' in data) {
        return ImageBlock.fromJSON(data);
    }
    else if ('video' in data) {
        return VideoBlock.fromJSON(data);
    }
    else if ('document' in data) {
        return DocumentBlock.fromJSON(data);
    }
    else if ('citations' in data) {
        return CitationsBlock.fromJSON(data);
    }
    else {
        throw new Error('Unknown ContentBlockData type');
    }
}
//# sourceMappingURL=messages.js.map