import path from "node:path";
import { Type } from "@sinclair/typebox";
import { loadConfig } from "../../config/config.js";
import { resolveSessionFilePath } from "../../config/sessions.js";
import { callGateway } from "../../gateway/call.js";
import { isSubagentSessionKey, resolveAgentIdFromSessionKey } from "../../routing/session-key.js";
import { jsonResult, readStringArrayParam } from "./common.js";
import { createAgentToAgentPolicy, classifySessionKind, deriveChannel, resolveDisplaySessionKey, resolveInternalSessionKey, resolveMainSessionAlias, stripToolMessages, } from "./sessions-helpers.js";
const SessionsListToolSchema = Type.Object({
    kinds: Type.Optional(Type.Array(Type.String())),
    limit: Type.Optional(Type.Number({ minimum: 1 })),
    activeMinutes: Type.Optional(Type.Number({ minimum: 1 })),
    messageLimit: Type.Optional(Type.Number({ minimum: 0 })),
});
function resolveSandboxSessionToolsVisibility(cfg) {
    return cfg.agents?.defaults?.sandbox?.sessionToolsVisibility ?? "spawned";
}
export function createSessionsListTool(opts) {
    return {
        label: "Sessions",
        name: "sessions_list",
        description: "List sessions with optional filters and last messages.",
        parameters: SessionsListToolSchema,
        execute: async (_toolCallId, args) => {
            const params = args;
            const cfg = loadConfig();
            const { mainKey, alias } = resolveMainSessionAlias(cfg);
            const visibility = resolveSandboxSessionToolsVisibility(cfg);
            const requesterInternalKey = typeof opts?.agentSessionKey === "string" && opts.agentSessionKey.trim()
                ? resolveInternalSessionKey({
                    key: opts.agentSessionKey,
                    alias,
                    mainKey,
                })
                : undefined;
            const restrictToSpawned = opts?.sandboxed === true &&
                visibility === "spawned" &&
                requesterInternalKey &&
                !isSubagentSessionKey(requesterInternalKey);
            const kindsRaw = readStringArrayParam(params, "kinds")?.map((value) => value.trim().toLowerCase());
            const allowedKindsList = (kindsRaw ?? []).filter((value) => ["main", "group", "cron", "hook", "node", "other"].includes(value));
            const allowedKinds = allowedKindsList.length ? new Set(allowedKindsList) : undefined;
            const limit = typeof params.limit === "number" && Number.isFinite(params.limit)
                ? Math.max(1, Math.floor(params.limit))
                : undefined;
            const activeMinutes = typeof params.activeMinutes === "number" && Number.isFinite(params.activeMinutes)
                ? Math.max(1, Math.floor(params.activeMinutes))
                : undefined;
            const messageLimitRaw = typeof params.messageLimit === "number" && Number.isFinite(params.messageLimit)
                ? Math.max(0, Math.floor(params.messageLimit))
                : 0;
            const messageLimit = Math.min(messageLimitRaw, 20);
            const list = (await callGateway({
                method: "sessions.list",
                params: {
                    limit,
                    activeMinutes,
                    includeGlobal: !restrictToSpawned,
                    includeUnknown: !restrictToSpawned,
                    spawnedBy: restrictToSpawned ? requesterInternalKey : undefined,
                },
            }));
            const sessions = Array.isArray(list?.sessions) ? list.sessions : [];
            const storePath = typeof list?.path === "string" ? list.path : undefined;
            const a2aPolicy = createAgentToAgentPolicy(cfg);
            const requesterAgentId = resolveAgentIdFromSessionKey(requesterInternalKey);
            const rows = [];
            for (const entry of sessions) {
                if (!entry || typeof entry !== "object")
                    continue;
                const key = typeof entry.key === "string" ? entry.key : "";
                if (!key)
                    continue;
                const entryAgentId = resolveAgentIdFromSessionKey(key);
                const crossAgent = entryAgentId !== requesterAgentId;
                if (crossAgent && !a2aPolicy.isAllowed(requesterAgentId, entryAgentId))
                    continue;
                if (key === "unknown")
                    continue;
                if (key === "global" && alias !== "global")
                    continue;
                const gatewayKind = typeof entry.kind === "string" ? entry.kind : undefined;
                const kind = classifySessionKind({ key, gatewayKind, alias, mainKey });
                if (allowedKinds && !allowedKinds.has(kind))
                    continue;
                const displayKey = resolveDisplaySessionKey({
                    key,
                    alias,
                    mainKey,
                });
                const entryChannel = typeof entry.channel === "string" ? entry.channel : undefined;
                const deliveryContext = entry.deliveryContext && typeof entry.deliveryContext === "object"
                    ? entry.deliveryContext
                    : undefined;
                const deliveryChannel = typeof deliveryContext?.channel === "string" ? deliveryContext.channel : undefined;
                const deliveryTo = typeof deliveryContext?.to === "string" ? deliveryContext.to : undefined;
                const deliveryAccountId = typeof deliveryContext?.accountId === "string" ? deliveryContext.accountId : undefined;
                const lastChannel = deliveryChannel ??
                    (typeof entry.lastChannel === "string" ? entry.lastChannel : undefined);
                const lastAccountId = deliveryAccountId ??
                    (typeof entry.lastAccountId === "string" ? entry.lastAccountId : undefined);
                const derivedChannel = deriveChannel({
                    key,
                    kind,
                    channel: entryChannel,
                    lastChannel,
                });
                const sessionId = typeof entry.sessionId === "string" ? entry.sessionId : undefined;
                const sessionFileRaw = entry.sessionFile;
                const sessionFile = typeof sessionFileRaw === "string" ? sessionFileRaw : undefined;
                let transcriptPath;
                if (sessionId && storePath) {
                    try {
                        transcriptPath = resolveSessionFilePath(sessionId, 
                        // @ts-ignore -- cherry-pick upstream type mismatch
                        // @ts-ignore -- cherry-pick upstream type mismatch
                        sessionFile ? { sessionFile } : undefined, {
                            agentId: resolveAgentIdFromSessionKey(key),
                            sessionsDir: path.dirname(storePath),
                        });
                    }
                    catch {
                        transcriptPath = undefined;
                    }
                }
                const row = {
                    key: displayKey,
                    kind,
                    channel: derivedChannel,
                    label: typeof entry.label === "string" ? entry.label : undefined,
                    displayName: typeof entry.displayName === "string" ? entry.displayName : undefined,
                    deliveryContext: deliveryChannel || deliveryTo || deliveryAccountId
                        ? {
                            channel: deliveryChannel,
                            to: deliveryTo,
                            accountId: deliveryAccountId,
                        }
                        : undefined,
                    updatedAt: typeof entry.updatedAt === "number" ? entry.updatedAt : undefined,
                    sessionId,
                    model: typeof entry.model === "string" ? entry.model : undefined,
                    contextTokens: typeof entry.contextTokens === "number" ? entry.contextTokens : undefined,
                    totalTokens: typeof entry.totalTokens === "number" ? entry.totalTokens : undefined,
                    thinkingLevel: typeof entry.thinkingLevel === "string" ? entry.thinkingLevel : undefined,
                    verboseLevel: typeof entry.verboseLevel === "string" ? entry.verboseLevel : undefined,
                    systemSent: typeof entry.systemSent === "boolean" ? entry.systemSent : undefined,
                    abortedLastRun: typeof entry.abortedLastRun === "boolean" ? entry.abortedLastRun : undefined,
                    sendPolicy: typeof entry.sendPolicy === "string" ? entry.sendPolicy : undefined,
                    lastChannel,
                    lastTo: deliveryTo ?? (typeof entry.lastTo === "string" ? entry.lastTo : undefined),
                    lastAccountId,
                    transcriptPath,
                };
                if (messageLimit > 0) {
                    const resolvedKey = resolveInternalSessionKey({
                        key: displayKey,
                        alias,
                        mainKey,
                    });
                    const history = (await callGateway({
                        method: "chat.history",
                        params: { sessionKey: resolvedKey, limit: messageLimit },
                    }));
                    const rawMessages = Array.isArray(history?.messages) ? history.messages : [];
                    const filtered = stripToolMessages(rawMessages);
                    row.messages = filtered.length > messageLimit ? filtered.slice(-messageLimit) : filtered;
                }
                rows.push(row);
            }
            return jsonResult({
                count: rows.length,
                sessions: rows,
            });
        },
    };
}
