import { registerServerToolHandler } from '../registry.js';
import { extractCapturedChatSeed } from './followup-request-builder.js';
import { ensureRuntimeMetadata, readRuntimeMetadata } from '../../conversion/runtime-metadata.js';
import { cloneJson } from '../server-side-tools.js';
const FLOW_ID = 'antigravity_thought_signature_bootstrap';
function readProviderKey(adapterContext) {
    if (!adapterContext || typeof adapterContext !== 'object') {
        return '';
    }
    const raw = adapterContext.providerKey ?? adapterContext.runtimeKey ?? adapterContext.providerId;
    return typeof raw === 'string' ? raw.trim() : '';
}
function isAntigravityFamily(providerKey) {
    const lowered = providerKey.toLowerCase();
    return lowered.startsWith('antigravity.') || lowered.startsWith('gemini-cli.');
}
function readErrorInfo(base) {
    const err = base.error;
    if (!err || typeof err !== 'object' || Array.isArray(err)) {
        return null;
    }
    const codeRaw = err.code;
    const msgRaw = err.message;
    const statusRaw = err.status ?? err.statusCode;
    const code = typeof codeRaw === 'string' ? codeRaw.trim() : typeof codeRaw === 'number' ? String(codeRaw) : undefined;
    const message = typeof msgRaw === 'string' ? msgRaw.trim() : undefined;
    const status = typeof statusRaw === 'number' && Number.isFinite(statusRaw)
        ? Math.floor(statusRaw)
        : typeof code === 'string' && /^HTTP_\d{3}$/i.test(code)
            ? Number(code.split('_')[1])
            : typeof code === 'string' && /^\d{3}$/.test(code)
                ? Number(code)
                : undefined;
    return { ...(status ? { status } : {}), ...(code ? { code } : {}), ...(message ? { message } : {}) };
}
function isSignatureInvalidError(error) {
    const code = (error.code || '').toLowerCase();
    if (code.includes('signature')) {
        return true;
    }
    const msg = (error.message || '').toLowerCase();
    return msg.includes('signature') && (msg.includes('invalid') || msg.includes('corrupt') || msg.includes('validator'));
}
function shouldTriggerBootstrap(error) {
    // One-shot bootstrap trigger:
    // - Always attempt once on 429 (may be quota OR signature validator; one-shot prevents loops).
    // - Also attempt on 400 when we can confidently classify as signature invalid/missing.
    if (error.status === 429)
        return true;
    if (error.status === 400 && isSignatureInvalidError(error))
        return true;
    return false;
}
function buildClockToolSchema() {
    // Keep this schema aligned with docs/SERVERTOOL_CLOCK_DESIGN.md + chat-process injection.
    return {
        type: 'function',
        function: {
            name: 'clock',
            description: 'Time + Alarm for this session. If waiting longer than 2 minutes is required, call clock.schedule now (do not only promise to wait). Format example: {"action":"schedule","items":[{"dueAt":"<ISO8601>","task":"<exact follow-up action>","tool":"<tool-name-or-empty>","arguments":"<json-string-or-{}>"}],"taskId":""}. Use get/schedule/update/list/cancel/clear. Scheduled reminders will be injected into future requests.',
            strict: true,
            parameters: {
                type: 'object',
                properties: {
                    action: {
                        type: 'string',
                        enum: ['get', 'schedule', 'update', 'list', 'cancel', 'clear'],
                        description: 'Get current time, or schedule/update/list/cancel/clear session-scoped reminders. If waiting longer than 2 minutes is required, use action="schedule" immediately.'
                    },
                    items: {
                        type: 'array',
                        description: 'For schedule/update: list of reminders (update uses items[0]).',
                        items: {
                            type: 'object',
                            properties: {
                                dueAt: {
                                    type: 'string',
                                    description: 'ISO8601 datetime with timezone (e.g. 2026-01-21T20:30:00-08:00).'
                                },
                                task: {
                                    type: 'string',
                                    description: 'Reminder text (should include which tool to use and what to do).'
                                },
                                tool: {
                                    type: 'string',
                                    description: 'Optional suggested tool name (hint only).'
                                },
                                arguments: {
                                    type: 'string',
                                    description: 'Optional suggested tool arguments as a JSON string (hint only). Use "{}" when unsure.'
                                }
                            },
                            required: ['dueAt', 'task', 'tool', 'arguments'],
                            additionalProperties: false
                        }
                    },
                    taskId: {
                        type: 'string',
                        description: 'For cancel/update: taskId to target.'
                    }
                },
                required: ['action', 'items', 'taskId'],
                additionalProperties: false
            }
        }
    };
}
function ensureClockTool(tools) {
    const list = Array.isArray(tools) ? cloneJson(tools) : [];
    const hasClock = list.some((tool) => {
        const fn = tool && typeof tool === 'object' && !Array.isArray(tool) ? tool.function : undefined;
        const name = fn && typeof fn === 'object' && typeof fn.name === 'string' ? String(fn.name) : '';
        return name.trim() === 'clock';
    });
    if (hasClock) {
        return list;
    }
    return [...list, buildClockToolSchema()];
}
const BOOTSTRAP_USER_PROMPT = '请先调用 `clock` 工具并传入 `{\"action\":\"get\",\"items\":[],\"taskId\":\"\"}` 获取当前时间；' +
    '得到工具返回后只需回复 `OK`（不要调用其它工具）。';
const handler = async (ctx) => {
    if (!ctx.capabilities.reenterPipeline) {
        return null;
    }
    if (ctx.providerProtocol !== 'gemini-chat') {
        return null;
    }
    const providerKey = readProviderKey(ctx.adapterContext);
    if (!providerKey || !isAntigravityFamily(providerKey)) {
        return null;
    }
    const rt = readRuntimeMetadata(ctx.adapterContext);
    if (rt?.serverToolFollowup === true) {
        return null;
    }
    if (rt?.antigravityThoughtSignatureBootstrapAttempted === true) {
        return null;
    }
    const error = readErrorInfo(ctx.base);
    if (!error || !shouldTriggerBootstrap(error)) {
        return null;
    }
    const captured = ctx.adapterContext?.capturedChatRequest;
    const seed = extractCapturedChatSeed(captured);
    if (!seed) {
        return null;
    }
    // Preflight bootstrap request:
    // - Avoid any historical tool calls so Gemini can emit a fresh thoughtSignature.
    // - Keep the FIRST user message identical to the original request to preserve derived session_id.
    const originalMessages = Array.isArray(seed.messages) ? cloneJson(seed.messages) : [];
    const firstUser = originalMessages.find((m) => {
        const role = typeof m?.role === 'string' ? String(m.role).toLowerCase() : '';
        return role === 'user';
    });
    if (!firstUser) {
        return null;
    }
    const messages = [cloneJson(firstUser), { role: 'user', content: BOOTSTRAP_USER_PROMPT }];
    const parameters = {
        ...(seed.parameters && typeof seed.parameters === 'object' && !Array.isArray(seed.parameters)
            ? cloneJson(seed.parameters)
            : {})
    };
    // Gemini toolConfig forcing: request the model to emit a clock call first, before any other tools.
    parameters.tool_config = {
        functionCallingConfig: {
            mode: 'ANY',
            allowedFunctionNames: ['clock']
        }
    };
    const followupPayload = {
        ...(seed.model ? { model: seed.model } : {}),
        messages,
        tools: ensureClockTool([]),
        ...(Object.keys(parameters).length ? { parameters } : {})
    };
    const followupMetadata = {
        __shadowCompareForcedProviderKey: providerKey
    };
    const followupRt = ensureRuntimeMetadata(followupMetadata);
    followupRt.antigravityThoughtSignatureBootstrap = true;
    followupRt.antigravityThoughtSignatureBootstrapAttempted = true;
    return {
        flowId: FLOW_ID,
        finalize: async () => ({
            chatResponse: ctx.base,
            execution: {
                flowId: FLOW_ID,
                followup: {
                    requestIdSuffix: ':antigravity_ts_bootstrap',
                    entryEndpoint: ctx.entryEndpoint,
                    payload: followupPayload,
                    metadata: followupMetadata
                }
            }
        })
    };
};
registerServerToolHandler(FLOW_ID, handler, { trigger: 'auto', hook: { phase: 'default', priority: 30 } });
