/**
 * Bedrock Chat Handler
 *
 * Executes chat requests against the Bedrock Converse API.
 */
import { validateBedrockConfig, getBedrockEndpoint } from "./config.js";
import { buildConverseRequest } from "./mapper.js";
import { signRequest } from "../../utils/AwsSigV4.js";
import { handleBedrockError } from "./Errors.js";
import { ModelRegistry } from "../../models/ModelRegistry.js";
import { fetchWithTimeout } from "../../utils/fetch.js";
import { logger } from "../../utils/logger.js";
// ─────────────────────────────────────────────────────────────────────────────
// Chat Handler
// ─────────────────────────────────────────────────────────────────────────────
export class BedrockChat {
    config;
    authMode;
    baseUrl;
    constructor(config) {
        this.config = config;
        this.authMode = validateBedrockConfig(config);
        this.baseUrl = getBedrockEndpoint(config.region);
    }
    /**
     * Execute a chat request against Bedrock Converse API.
     */
    async execute(request) {
        const modelId = request.model;
        const url = `${this.baseUrl}/model/${modelId}/converse`;
        // Build the Bedrock request body
        const guardrail = this.config.guardrailIdentifier && this.config.guardrailVersion
            ? {
                guardrailIdentifier: this.config.guardrailIdentifier,
                guardrailVersion: this.config.guardrailVersion
            }
            : undefined;
        const body = buildConverseRequest(request.messages, request.tools, {
            maxTokens: request.max_tokens,
            temperature: request.temperature,
            thinking: request.thinking,
            guardrail,
            additionalModelRequestFields: request.additionalModelRequestFields
        });
        const bodyJson = JSON.stringify(body);
        // Build headers based on auth mode
        const headers = this.buildHeaders(url, bodyJson, request.headers);
        logger.logRequest("Bedrock", "POST", url, body);
        // Make the request
        const response = await fetchWithTimeout(url, {
            method: "POST",
            headers,
            body: bodyJson
        }, request.requestTimeout ?? this.config.requestTimeout);
        if (!response.ok) {
            await handleBedrockError(response, modelId);
        }
        const json = (await response.json());
        logger.logResponse("Bedrock", response.status, response.statusText, json);
        const result = this.parseResponse(json);
        if (result.usage) {
            result.usage = ModelRegistry.calculateCost(result.usage, modelId, "bedrock");
        }
        return result;
    }
    /**
     * Build request headers based on auth mode.
     */
    buildHeaders(url, body, additionalHeaders) {
        const headers = {
            "Content-Type": "application/json",
            Accept: "application/json",
            ...additionalHeaders
        };
        if (this.authMode === "apiKey") {
            // Simple Bearer token auth
            headers["Authorization"] = `Bearer ${this.config.apiKey}`;
        }
        else {
            // SigV4 signing
            const credentials = {
                accessKeyId: this.config.accessKeyId,
                secretAccessKey: this.config.secretAccessKey,
                sessionToken: this.config.sessionToken
            };
            const signedHeaders = signRequest({
                method: "POST",
                url,
                body,
                credentials,
                region: this.config.region,
                service: "bedrock"
            });
            // Merge signed headers
            headers["host"] = signedHeaders.host;
            headers["x-amz-date"] = signedHeaders["x-amz-date"];
            headers["x-amz-content-sha256"] = signedHeaders["x-amz-content-sha256"];
            headers["Authorization"] = signedHeaders.authorization;
            if (signedHeaders["x-amz-security-token"]) {
                headers["x-amz-security-token"] = signedHeaders["x-amz-security-token"];
            }
        }
        return headers;
    }
    /**
     * Parse Bedrock response to NodeLLM format.
     */
    parseResponse(response) {
        const message = response.output.message;
        let content = null;
        let thinkingText = null;
        const toolCalls = [];
        // Process content blocks
        for (const block of message.content) {
            if (block.text) {
                content = content ? content + block.text : block.text;
            }
            if (block.reasoningContent?.text) {
                thinkingText = thinkingText
                    ? thinkingText + block.reasoningContent.text
                    : block.reasoningContent.text;
            }
            if (block.toolUse) {
                toolCalls.push({
                    id: block.toolUse.toolUseId,
                    type: "function",
                    function: {
                        name: block.toolUse.name,
                        arguments: JSON.stringify(block.toolUse.input)
                    }
                });
            }
        }
        // Build usage info
        const usage = {
            input_tokens: response.usage.inputTokens,
            output_tokens: response.usage.outputTokens,
            total_tokens: response.usage.totalTokens,
            cached_tokens: response.usage.cacheReadInputTokens,
            cache_creation_tokens: response.usage.cacheWriteInputTokens
        };
        return {
            content,
            thinking: thinkingText ? { text: thinkingText } : undefined,
            reasoning: thinkingText || undefined, // Keep deprecated field for compat
            tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
            usage,
            finish_reason: response.stopReason,
            metadata: response.trace ? { trace: response.trace } : undefined
        };
    }
}
