import { query } from '@anthropic-ai/claude-agent-sdk';
import { coerceNumber, normalizeString } from './utils';
const buildSystemPrompt = (options, input) => {
    const segments = [];
    if (normalizeString(options.instructions)) {
        segments.push(options.instructions.trim());
    }
    for (const message of input.messages) {
        if (message.role === 'system' && normalizeString(message.content)) {
            segments.push(message.content.trim());
        }
    }
    if (segments.length === 0) {
        return undefined;
    }
    return segments.join('\n\n');
};
const buildConversationPrompt = (input) => {
    const segments = [];
    for (const message of input.messages) {
        if (message.role !== 'user' && message.role !== 'assistant') {
            continue;
        }
        const header = message.role === 'user' ? 'User' : 'Assistant';
        const body = normalizeString(message.content) ?? '';
        segments.push(`${header}: ${body.length > 0 ? body : '[No content]'}`);
    }
    return segments.join('\n\n').trim();
};
const extractAssistantMessageText = (item) => {
    const message = item.message;
    if (!message || typeof message !== 'object') {
        return '';
    }
    const content = message.content;
    if (!Array.isArray(content)) {
        return '';
    }
    const parts = [];
    for (const entry of content) {
        if (!entry || typeof entry !== 'object')
            continue;
        const kind = typeof entry.type === 'string'
            ? entry.type
            : undefined;
        if (kind === 'text') {
            const textValue = typeof entry.text === 'string'
                ? entry.text
                : '';
            if (textValue) {
                parts.push(textValue);
            }
        }
    }
    return parts.join('');
};
const extractTextDeltaFromEventRecord = (record) => {
    const type = typeof record.type === 'string' ? record.type : undefined;
    if (type === 'raw_model_stream_event' && record.data && typeof record.data === 'object') {
        return extractTextDeltaFromEventRecord(record.data);
    }
    if (type === 'content_block_delta') {
        const delta = record.delta;
        if (delta && typeof delta === 'object') {
            const deltaType = typeof delta.type === 'string' ? delta.type : undefined;
            if (deltaType === 'text_delta') {
                const text = delta.text;
                return typeof text === 'string' ? text : null;
            }
        }
    }
    if (type && type.includes('output_text') && type.includes('delta')) {
        const delta = record.delta;
        if (typeof delta === 'string') {
            return delta;
        }
        if (delta && typeof delta === 'object') {
            const text = delta.text;
            if (typeof text === 'string') {
                return text;
            }
        }
    }
    if (type === 'model') {
        if (record.event && typeof record.event === 'object') {
            const nested = extractTextDeltaFromEventRecord(record.event);
            if (nested) {
                return nested;
            }
        }
    }
    if (!type && record.delta) {
        const delta = record.delta;
        if (typeof delta === 'string') {
            return delta;
        }
        if (delta && typeof delta === 'object') {
            const text = delta.text;
            if (typeof text === 'string') {
                return text;
            }
        }
    }
    return null;
};
const extractTextDeltaFromStreamItem = (item) => {
    const event = item.event;
    if (!event || typeof event !== 'object') {
        return null;
    }
    return extractTextDeltaFromEventRecord(event);
};
export const startAnthropicStream = (agent, input, callbacks) => {
    const controller = input.abortController ?? new AbortController();
    const signal = input.signal ?? controller.signal;
    const { options } = agent;
    const prompt = buildConversationPrompt(input);
    if (!prompt) {
        throw new Error('Anthropic provider requires at least one user or assistant message in the thread');
    }
    const systemPrompt = buildSystemPrompt(options, input);
    const modelSettings = options.modelSettings;
    const connectionSettings = options.connection;
    const pickNumeric = (keys) => {
        const sources = [modelSettings, connectionSettings];
        for (const source of sources) {
            if (!source)
                continue;
            for (const key of keys) {
                if (key in source) {
                    return coerceNumber(source[key], NaN);
                }
            }
        }
        return undefined;
    };
    const extraArgs = {};
    const applyNumericArg = (keys, argName) => {
        const value = pickNumeric(keys);
        if (typeof value === 'number' && Number.isFinite(value)) {
            extraArgs[argName] = String(value);
        }
    };
    applyNumericArg(['max_output_tokens', 'maxTokens', 'max_tokens'], 'max-output-tokens');
    applyNumericArg(['temperature', 'temp'], 'temperature');
    applyNumericArg(['top_p', 'topP'], 'top-p');
    applyNumericArg(['top_k', 'topK'], 'top-k');
    const envOverrides = {};
    // if (agent.baseURL && agent.baseURL !== DEFAULT_BASE_URL) {
    //   envOverrides.ANTHROPIC_API_URL = agent.baseURL
    //   envOverrides.ANTHROPIC_BASE_URL = agent.baseURL
    // }
    if (connectionSettings) {
        for (const [key, value] of Object.entries(connectionSettings)) {
            if (typeof value === 'string' && value.trim().length > 0 && !(key in envOverrides)) {
                envOverrides[key] = value;
            }
        }
    }
    console.log('ENV OVERRIDES:', envOverrides);
    let env;
    if (Object.keys(envOverrides).length > 0) {
        const baseEnv = Object.fromEntries(Object.entries(process.env).filter(([, value]) => typeof value === 'string'));
        env = { ...baseEnv, ...envOverrides };
    }
    console.log('FINAL ENV:', env);
    const queryOptions = {
        abortController: controller,
        includePartialMessages: true,
        systemPrompt,
        model: options.modelName,
        ...(env ? { env } : {}),
        extraArgs
    };
    let finalOutput = '';
    let messageCreated = false;
    console.log('QUERY OPTIONS:', queryOptions);
    const stream = query({
        prompt,
        options: queryOptions
    });
    const streamPromise = (async () => {
        try {
            for await (const item of stream) {
                const type = typeof item.type === 'string' ? item.type : undefined;
                if (type === 'stream_event') {
                    const delta = extractTextDeltaFromStreamItem(item);
                    if (delta) {
                        finalOutput += delta;
                        if (callbacks.onOutputTextDelta) {
                            await callbacks.onOutputTextDelta(delta);
                        }
                    }
                    continue;
                }
                if (type === 'assistant') {
                    const messageText = extractAssistantMessageText(item);
                    if (messageText.length > 0) {
                        finalOutput = messageText;
                        if (callbacks.onMessageOutputCreated) {
                            await callbacks.onMessageOutputCreated(finalOutput);
                            messageCreated = true;
                        }
                    }
                    continue;
                }
                if (type === 'result') {
                    if (!messageCreated && finalOutput.length > 0 && callbacks.onMessageOutputCreated) {
                        await callbacks.onMessageOutputCreated(finalOutput);
                        messageCreated = true;
                    }
                    if (callbacks.onFinalOutputAccessed) {
                        await callbacks.onFinalOutputAccessed(finalOutput);
                    }
                    continue;
                }
            }
            if (!messageCreated && finalOutput.length > 0 && callbacks.onMessageOutputCreated) {
                await callbacks.onMessageOutputCreated(finalOutput);
                messageCreated = true;
            }
            if (callbacks.onFinalOutputAccessed) {
                await callbacks.onFinalOutputAccessed(finalOutput);
            }
        }
        catch (error) {
            if (signal?.aborted) {
                if (error instanceof Error) {
                    if (error.name === 'AbortError') {
                        return;
                    }
                    if (error.message && error.message.toLowerCase().includes('aborted')) {
                        return;
                    }
                }
            }
            throw error;
        }
    })();
    return {
        cancel: async () => {
            if (!signal.aborted) {
                if (input.abortController) {
                    input.abortController.abort();
                }
                else {
                    controller.abort();
                }
            }
            if (typeof stream.interrupt === 'function') {
                try {
                    await stream.interrupt();
                }
                catch (error) {
                    if (!(error instanceof Error && error.name === 'AbortError')) {
                        throw error;
                    }
                }
            }
            try {
                await streamPromise;
            }
            catch (error) {
                if (!(error instanceof Error && error.name === 'AbortError')) {
                    throw error;
                }
            }
        },
        completed: streamPromise,
        signal: controller.signal
    };
};
