import { ANTIGRAVITY_GLOBAL_ALIAS_KEY, cacheAntigravityRequestSessionMeta, clearAntigravitySessionSignature, extractAntigravityGeminiSessionId, getAntigravityLatestSignatureSessionIdForAlias, lookupAntigravitySessionSignatureEntry, markAntigravitySessionSignatureRewind, shouldTreatAsMissingThoughtSignature } from '../antigravity-session-signature.js';
function isRecord(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function shouldEnableForAdapter(adapterContext) {
    if (!adapterContext) {
        return false;
    }
    const protocol = typeof adapterContext.providerProtocol === 'string' ? adapterContext.providerProtocol.trim().toLowerCase() : '';
    if (protocol !== 'gemini-chat') {
        return false;
    }
    const ctxAny = adapterContext;
    const providerIdOrKeyRaw = typeof ctxAny.providerId === 'string'
        ? String(ctxAny.providerId)
        : typeof ctxAny.providerKey === 'string'
            ? String(ctxAny.providerKey)
            : typeof ctxAny.runtimeKey === 'string'
                ? String(ctxAny.runtimeKey)
                : '';
    const providerIdOrKey = providerIdOrKeyRaw.trim().toLowerCase();
    const effectiveProviderId = providerIdOrKey.split('.')[0] ?? '';
    // Antigravity-Manager alignment: thoughtSignature compat applies to both Antigravity and Gemini CLI
    // (both route to Google Gemini internals that enforce thoughtSignature on tool loops).
    return effectiveProviderId === 'antigravity' || effectiveProviderId === 'gemini-cli';
}
function shouldEnableSignatureRecovery(adapterContext) {
    if (!adapterContext) {
        return false;
    }
    const ctxAny = adapterContext;
    const rtRaw = ctxAny.__rt;
    if (!rtRaw || typeof rtRaw !== 'object' || Array.isArray(rtRaw)) {
        return false;
    }
    const rt = rtRaw;
    return rt.antigravityThoughtSignatureRecovery === true;
}
function locateGeminiContentsNode(root) {
    if (Array.isArray(root.contents)) {
        return root;
    }
    const req = root.request;
    if (isRecord(req) && Array.isArray(req.contents)) {
        return req;
    }
    const data = root.data;
    if (isRecord(data)) {
        return locateGeminiContentsNode(data);
    }
    return undefined;
}
function resolveAntigravityAliasKey(adapterContext) {
    if (!adapterContext) {
        return 'antigravity.unknown';
    }
    const ctxAny = adapterContext;
    const candidates = [ctxAny.runtimeKey, ctxAny.providerKey, ctxAny.providerId].filter((v) => typeof v === 'string');
    for (const value of candidates) {
        const trimmed = value.trim();
        if (!trimmed)
            continue;
        const lower = trimmed.toLowerCase();
        if (lower.startsWith('antigravity.')) {
            const parts = trimmed.split('.');
            if (parts.length >= 2 && parts[0] && parts[1]) {
                return `${parts[0].trim()}.${parts[1].trim()}`;
            }
        }
        return trimmed;
    }
    return 'antigravity.unknown';
}
function stripThoughtSignatures(contentsNode) {
    const contentsRaw = contentsNode.contents;
    if (!Array.isArray(contentsRaw)) {
        return;
    }
    const contents = contentsRaw;
    for (const entry of contents) {
        if (!isRecord(entry))
            continue;
        const partsRaw = entry.parts;
        if (!Array.isArray(partsRaw))
            continue;
        const parts = partsRaw;
        for (const part of parts) {
            if (!isRecord(part))
                continue;
            if ('thoughtSignature' in part) {
                delete part.thoughtSignature;
            }
            if ('thought_signature' in part) {
                delete part.thought_signature;
            }
        }
    }
}
const ANTIGRAVITY_SIGNATURE_RECOVERY_PROMPT = "\n\n[System Recovery] Your previous output contained an invalid signature. Please regenerate the response without the corrupted signature block.";
function injectSignatureRecoveryPrompt(contentsNode) {
    const contentsRaw = contentsNode.contents;
    if (!Array.isArray(contentsRaw) || contentsRaw.length === 0) {
        return;
    }
    const contents = contentsRaw;
    const last = contents[contents.length - 1];
    if (!isRecord(last)) {
        return;
    }
    const partsRaw = last.parts;
    if (!Array.isArray(partsRaw)) {
        last.parts = [];
    }
    const parts = (Array.isArray(last.parts) ? last.parts : []);
    const alreadyInjected = parts.some((part) => {
        if (!isRecord(part))
            return false;
        const text = typeof part.text === 'string' ? String(part.text) : '';
        return text.includes('[System Recovery]');
    });
    if (alreadyInjected) {
        return;
    }
    parts.push({ text: ANTIGRAVITY_SIGNATURE_RECOVERY_PROMPT });
    last.parts = parts;
}
function injectThoughtSignatureIntoFunctionCalls(contentsNode, signature) {
    const contentsRaw = contentsNode.contents;
    if (!Array.isArray(contentsRaw)) {
        return;
    }
    const contents = contentsRaw;
    for (const entry of contents) {
        if (!isRecord(entry))
            continue;
        const partsRaw = entry.parts;
        if (!Array.isArray(partsRaw))
            continue;
        const parts = partsRaw;
        for (const part of parts) {
            if (!isRecord(part))
                continue;
            if (!isRecord(part.functionCall))
                continue;
            const existing = part.thoughtSignature;
            if (!shouldTreatAsMissingThoughtSignature(existing)) {
                continue;
            }
            part.thoughtSignature = signature;
        }
    }
}
export function prepareAntigravityThoughtSignatureForGeminiRequest(payload, adapterContext) {
    if (!shouldEnableForAdapter(adapterContext)) {
        return payload;
    }
    const aliasKey = resolveAntigravityAliasKey(adapterContext);
    // Antigravity-Manager alignment: sessionId is derived from the first user text (or JSON fallback),
    // not from external session/conversation identifiers injected by other clients/hosts.
    const originalSessionId = extractAntigravityGeminiSessionId(payload);
    let sessionId = originalSessionId;
    let usedLeasedSession = false;
    const ctxAny = adapterContext;
    const keys = [
        adapterContext.requestId,
        typeof ctxAny.clientRequestId === 'string' ? String(ctxAny.clientRequestId) : '',
        typeof ctxAny.groupRequestId === 'string' ? String(ctxAny.groupRequestId) : ''
    ].filter((k) => typeof k === 'string' && k.trim().length);
    const root = payload;
    const contentsNode = locateGeminiContentsNode(root);
    const messageCount = contentsNode && Array.isArray(contentsNode.contents) ? contentsNode.contents.length : 1;
    // Recovery mode: strip any user-provided / stale signatures and do not lease/inject from cache.
    if (shouldEnableSignatureRecovery(adapterContext)) {
        if (contentsNode) {
            stripThoughtSignatures(contentsNode);
            // Antigravity-Manager alignment: append a repair hint so Gemini can regenerate without a corrupted signature.
            injectSignatureRecoveryPrompt(contentsNode);
        }
        for (const key of keys) {
            cacheAntigravityRequestSessionMeta(key, { aliasKey, sessionId: originalSessionId, messageCount });
        }
        return payload;
    }
    const resolveLookup = (sid) => {
        const direct = lookupAntigravitySessionSignatureEntry(aliasKey, sid, { hydrate: true });
        if (typeof direct.signature === 'string' && direct.signature.trim().length) {
            return direct;
        }
        return lookupAntigravitySessionSignatureEntry(ANTIGRAVITY_GLOBAL_ALIAS_KEY, sid, { hydrate: true });
    };
    let lookup = resolveLookup(sessionId);
    const hasSignature = typeof lookup.signature === 'string' && lookup.signature.trim().length && typeof lookup.messageCount === 'number';
    if (!hasSignature) {
        // Requested behavior:
        // - Once an alias has ever obtained a signature, remember its sessionId.
        // - For new sessions hitting the same alias, temporarily use that signature sessionId.
        // This avoids cold-start tool-call failures when the current request's derived sessionId has no cached signature yet.
        const leasedSessionId = getAntigravityLatestSignatureSessionIdForAlias(aliasKey, { hydrate: true });
        if (leasedSessionId && leasedSessionId.trim().length && leasedSessionId.trim() !== sessionId) {
            const leasedLookup = resolveLookup(leasedSessionId.trim());
            const leasedHasSignature = typeof leasedLookup.signature === 'string' &&
                leasedLookup.signature.trim().length &&
                typeof leasedLookup.messageCount === 'number';
            if (leasedHasSignature) {
                sessionId = leasedSessionId.trim();
                lookup = leasedLookup;
                usedLeasedSession = true;
            }
        }
    }
    const effectiveSessionId = sessionId;
    for (const key of keys) {
        cacheAntigravityRequestSessionMeta(key, { aliasKey, sessionId: effectiveSessionId, messageCount });
    }
    const cached = typeof lookup.signature === 'string' && typeof lookup.messageCount === 'number'
        ? { signature: lookup.signature, messageCount: lookup.messageCount }
        : undefined;
    if (!cached) {
        return payload;
    }
    // Rewind detection is meaningful within the SAME session. When we lease a prior sessionId to reuse
    // an existing signature, messageCount comparisons may be unrelated and should not invalidate the cache.
    if (!usedLeasedSession && typeof messageCount === 'number' && messageCount > 0 && messageCount < cached.messageCount) {
        // Rewind detected: do not inject a "future" signature; clear and wait for a fresh signature from upstream.
        clearAntigravitySessionSignature(aliasKey, effectiveSessionId);
        markAntigravitySessionSignatureRewind(aliasKey, effectiveSessionId, messageCount);
        // Antigravity-Manager alignment: global signature store must also be blocked on rewinds.
        clearAntigravitySessionSignature(ANTIGRAVITY_GLOBAL_ALIAS_KEY, effectiveSessionId);
        markAntigravitySessionSignatureRewind(ANTIGRAVITY_GLOBAL_ALIAS_KEY, effectiveSessionId, messageCount);
        return payload;
    }
    if (!contentsNode) {
        return payload;
    }
    injectThoughtSignatureIntoFunctionCalls(contentsNode, cached.signature);
    return payload;
}
