import { applyToolTextRequestGuidance } from './tool-text-request-guidance.js';
const DEFAULT_OPTIONS = {
    strictToolRequired: true,
    toolProtocol: undefined
};
const SEARCH_ROUTE_PREFIXES = ['web_search', 'search'];
const readString = (value) => {
    if (typeof value !== 'string') {
        return undefined;
    }
    const trimmed = value.trim();
    return trimmed.length ? trimmed : undefined;
};
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
function readBoolean(input, fallback) {
    if (typeof input === 'boolean') {
        return input;
    }
    if (typeof input === 'string') {
        const normalized = input.trim().toLowerCase();
        if (['true', '1', 'yes', 'on'].includes(normalized)) {
            return true;
        }
        if (['false', '0', 'no', 'off'].includes(normalized)) {
            return false;
        }
    }
    return fallback;
}
function readOptionalBoolean(input) {
    if (typeof input === 'boolean') {
        return input;
    }
    if (typeof input === 'string') {
        const normalized = input.trim().toLowerCase();
        if (['true', '1', 'yes', 'on'].includes(normalized)) {
            return true;
        }
        if (['false', '0', 'no', 'off'].includes(normalized)) {
            return false;
        }
    }
    return undefined;
}
function readToolProtocol(input) {
    if (typeof input !== 'string') {
        return undefined;
    }
    const normalized = input.trim().toLowerCase();
    if (normalized === 'text' || normalized === 'native') {
        return normalized;
    }
    return undefined;
}
function resolveOptions(adapterContext) {
    const context = (adapterContext ?? {});
    const deepseekNode = isRecord(context.deepseek)
        ? context.deepseek
        : isRecord(context.__rt) && isRecord(context.__rt.deepseek)
            ? context.__rt.deepseek
            : undefined;
    if (!deepseekNode) {
        return { ...DEFAULT_OPTIONS };
    }
    const legacyFallback = readOptionalBoolean(deepseekNode.textToolFallback);
    const toolProtocol = readToolProtocol(deepseekNode.toolProtocol) ??
        (legacyFallback !== undefined ? (legacyFallback ? 'text' : 'native') : undefined);
    return {
        strictToolRequired: readBoolean(deepseekNode.strictToolRequired, DEFAULT_OPTIONS.strictToolRequired),
        toolProtocol
    };
}
function normalizeContentToText(content) {
    if (typeof content === 'string') {
        return content;
    }
    if (content === null || content === undefined) {
        return '';
    }
    if (Array.isArray(content)) {
        const parts = [];
        for (const item of content) {
            if (!isRecord(item)) {
                continue;
            }
            const type = readString(item.type)?.toLowerCase();
            if ((type === 'text' || type === 'input_text' || type === 'output_text') && readString(item.text)) {
                parts.push(readString(item.text));
                continue;
            }
            if (readString(item.content)) {
                parts.push(readString(item.content));
                continue;
            }
            if (type === 'tool_result' && item.content !== undefined) {
                parts.push(stringifyUnknown(item.content));
            }
        }
        return parts.join('\n').trim();
    }
    return stringifyUnknown(content);
}
function stringifyUnknown(value) {
    if (typeof value === 'string') {
        return value;
    }
    if (value === null || value === undefined) {
        return '';
    }
    try {
        return JSON.stringify(value);
    }
    catch {
        return String(value);
    }
}
function normalizeToolCallsAsText(toolCallsRaw) {
    if (!Array.isArray(toolCallsRaw) || toolCallsRaw.length === 0) {
        return '';
    }
    const toolCalls = toolCallsRaw
        .filter((item) => isRecord(item))
        .map((item) => {
        const fn = isRecord(item.function) ? item.function : undefined;
        const name = readString(fn?.name);
        if (!name) {
            return null;
        }
        const argsRaw = fn?.arguments;
        let input = {};
        if (typeof argsRaw === 'string') {
            const trimmed = argsRaw.trim();
            if (trimmed.length) {
                try {
                    input = JSON.parse(trimmed);
                }
                catch {
                    input = { _raw: trimmed };
                }
            }
        }
        else if (argsRaw !== undefined) {
            input = argsRaw;
        }
        return { name, input };
    })
        .filter((item) => Boolean(item));
    if (!toolCalls.length) {
        return '';
    }
    try {
        return JSON.stringify({ tool_calls: toolCalls });
    }
    catch {
        return '';
    }
}
function toPromptMessages(root, options) {
    const messagesRaw = Array.isArray(root.messages) ? root.messages : [];
    const messages = [];
    for (const item of messagesRaw) {
        if (!isRecord(item)) {
            continue;
        }
        const role = readString(item.role)?.toLowerCase() ?? '';
        if (!role) {
            continue;
        }
        const contentText = normalizeContentToText(item.content);
        const toolCallsText = normalizeToolCallsAsText(item.tool_calls);
        const reasoning = readString(item.reasoning_content) ?? readString(item.reasoning) ?? '';
        const parts = [contentText];
        if (toolCallsText) {
            parts.push(toolCallsText);
        }
        if (reasoning) {
            parts.push(reasoning);
        }
        const text = parts.filter(Boolean).join('\n').trim();
        messages.push({ role, text });
    }
    return messages;
}
function mergeByRole(messages) {
    if (!messages.length) {
        return [];
    }
    const merged = [{ ...messages[0] }];
    for (const item of messages.slice(1)) {
        const last = merged[merged.length - 1];
        if (last.role === item.role) {
            last.text = [last.text, item.text].filter(Boolean).join('\n\n');
        }
        else {
            merged.push({ ...item });
        }
    }
    return merged;
}
function buildPromptFromMessages(messages) {
    const merged = mergeByRole(messages);
    const parts = [];
    merged.forEach((block, index) => {
        const role = block.role;
        const text = block.text ?? '';
        if (role === 'assistant') {
            parts.push(`<｜Assistant｜>${text}<｜end▁of▁sentence｜>`);
            return;
        }
        if (role === 'user' || role === 'system' || role === 'tool') {
            if (index > 0) {
                parts.push(`<｜User｜>${text}`);
            }
            else {
                parts.push(text);
            }
            return;
        }
        parts.push(text);
    });
    return parts
        .join('')
        .replace(/!\[(.*?)\]\((.*?)\)/g, '[$1]($2)')
        .trim();
}
function resolveModel(payload, adapterContext) {
    const direct = readString(payload.model);
    if (direct) {
        return direct;
    }
    const context = (adapterContext ?? {});
    return readString(context.modelId) ?? readString(context.originalModelId) ?? '';
}
function resolveThinkingSearchFlags(modelRaw) {
    const model = modelRaw.trim().toLowerCase();
    if (model === 'deepseek-v3' || model === 'deepseek-chat') {
        return { thinking: false, search: false };
    }
    if (model === 'deepseek-r1' || model === 'deepseek-reasoner') {
        return { thinking: true, search: false };
    }
    if (model === 'deepseek-v3-search' || model === 'deepseek-chat-search') {
        return { thinking: false, search: true };
    }
    if (model === 'deepseek-r1-search' || model === 'deepseek-reasoner-search') {
        return { thinking: true, search: true };
    }
    return { thinking: false, search: false };
}
function shouldForceSearch(root, adapterContext) {
    const routeId = readString(adapterContext?.routeId)?.toLowerCase() ?? '';
    if (SEARCH_ROUTE_PREFIXES.some((prefix) => routeId.startsWith(prefix))) {
        return true;
    }
    if (isRecord(root.web_search)) {
        return true;
    }
    const context = (adapterContext ?? {});
    if (isRecord(context.__rt) && context.__rt.forceWebSearch === true) {
        return true;
    }
    return false;
}
export function applyDeepSeekWebRequestTransform(payload, adapterContext) {
    if (!payload || typeof payload !== 'object') {
        return payload;
    }
    const root = structuredClone(payload);
    const options = resolveOptions(adapterContext);
    const guidedRoot = options.toolProtocol === 'text'
        ? applyToolTextRequestGuidance(root, { enabled: true })
        : root;
    const model = resolveModel(guidedRoot, adapterContext);
    const flags = resolveThinkingSearchFlags(model);
    const forceSearch = shouldForceSearch(guidedRoot, adapterContext);
    const prompt = buildPromptFromMessages(toPromptMessages(guidedRoot, options));
    const next = {
        ...(readString(guidedRoot.chat_session_id) ? { chat_session_id: readString(guidedRoot.chat_session_id) } : {}),
        parent_message_id: readString(guidedRoot.parent_message_id) ?? null,
        prompt,
        ref_file_ids: Array.isArray(guidedRoot.ref_file_ids) ? guidedRoot.ref_file_ids : [],
        thinking_enabled: flags.thinking,
        search_enabled: forceSearch ? true : flags.search
    };
    if (guidedRoot.stream === true) {
        next.stream = true;
    }
    // Preserve a tiny runtime hint surface for response-side strict/fallback checks.
    next.metadata = {
        ...(isRecord(guidedRoot.metadata) ? guidedRoot.metadata : {}),
        deepseek: {
            strictToolRequired: options.strictToolRequired,
            ...(options.toolProtocol ? { toolProtocol: options.toolProtocol } : {})
        }
    };
    return next;
}
