import { friendlyErrorText } from "../../core/error-messages.js";
import { RemoteRelayClient } from "../../peers/peer-client.js";
import { peerPromptProxyPayload } from "../../runtime/remote-prompt.js";
import { remotePeerThreadSourceContextKey } from "./channel-peer-context.js";
export async function runChannelPeerPrompt(options) {
    if (!options.targetPeerId) {
        return false;
    }
    if (options.canUsePeer && !options.canUsePeer(options.targetPeerId)) {
        await options.sendFailure(`Access denied for peer target: ${options.targetPeerId}.`);
        return true;
    }
    const client = options.remoteClient ?? new RemoteRelayClient();
    const sourceContextKey = remotePeerThreadSourceContextKey(options.contextKey, options.targetThreadId);
    let responseMessageId;
    let accumulated = "";
    let lastEditAt = 0;
    let completed = false;
    let closeSubscription = () => { };
    const typing = setInterval(() => {
        void options.sendTyping().catch(() => { });
    }, options.typingIntervalMs);
    typing.unref?.();
    void options.sendTyping().catch(() => { });
    const flush = async (force = false) => {
        if (!accumulated.trim()) {
            return;
        }
        const now = Date.now();
        if (!force && now - lastEditAt < options.editMinIntervalMs) {
            return;
        }
        if (responseMessageId === undefined) {
            responseMessageId = await options.sendResponse(accumulated);
        }
        else {
            await options.editResponse(responseMessageId, accumulated);
        }
        lastEditAt = now;
    };
    const done = new Promise((resolve) => {
        const timeout = setTimeout(resolve, 30 * 60 * 1000);
        timeout.unref?.();
        let subscription;
        const finish = () => {
            clearTimeout(timeout);
            subscription?.close();
            resolve();
        };
        subscription = client.subscribe(options.targetPeerId, (event) => {
            if (event.type === "turn_start") {
                void options.sendTurnStart(event.prompt).catch(() => { });
            }
            else if (event.type === "text_delta") {
                accumulated += event.delta;
                void flush(false).catch(() => { });
            }
            else if (event.type === "tool_start") {
                if (currentMirrorMode(options) === "full") {
                    void options.sendToolStart(event.toolName).catch(() => { });
                }
            }
            else if (event.type === "turn_complete") {
                completed = true;
                finish();
            }
            else if (event.type === "turn_error") {
                accumulated += `\n\nError: ${event.error}`;
                completed = true;
                finish();
            }
        }, (error) => {
            accumulated += `\n\nRemote event stream failed: ${error.message}`;
            finish();
        }, sourceContextKey);
        closeSubscription = () => subscription?.close();
    });
    try {
        const result = await client.webProxy(options.targetPeerId, await peerPromptProxyPayload(options.prompt), options.prompt.activityActor, sourceContextKey);
        if (isQueuedRemoteResult(result)) {
            closeSubscription();
            await options.sendQueued(String(result.queueId ?? ""));
            return true;
        }
        await done;
        await flush(true);
        if (!accumulated.trim() && completed) {
            await options.sendCompleted();
        }
        return true;
    }
    catch (error) {
        await options.sendFailure(friendlyErrorText(error));
        return true;
    }
    finally {
        clearInterval(typing);
        closeSubscription();
    }
}
function isQueuedRemoteResult(value) {
    return Boolean(value && typeof value === "object" && "queued" in value && value.queued);
}
function currentMirrorMode(options) {
    if (typeof options.mirrorMode === "function") {
        return options.mirrorMode();
    }
    return options.mirrorMode ?? "full";
}
