/**
 * Auto-Session Tracking
 *
 * Automatically detects agent session boundaries by monitoring tool calls.
 * Sessions auto-start when card-mutating tools are called, and auto-end
 * after 10 minutes of inactivity or when a different card is worked on.
 */
/** Tools that trigger auto-start of a session */
export const AUTO_START_TRIGGERS = new Set([
    "harmony_generate_prompt",
    "harmony_update_card",
    "harmony_move_card",
    "harmony_create_subtask",
    "harmony_toggle_subtask",
    "harmony_add_label_to_card",
    "harmony_remove_label_from_card",
]);
export const INACTIVITY_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
const CHECK_INTERVAL_MS = 60 * 1000; // 60 seconds
const activeSessions = new Map();
let inactivityTimer = null;
let endCallback = null;
let clientGetter = null;
/**
 * Initialize auto-session tracking.
 * @param callback Called when an auto-session ends (runs the learning pipeline)
 * @param getClient Function to get the current API client
 */
export function initAutoSession(callback, getClient) {
    endCallback = callback;
    clientGetter = getClient;
    if (inactivityTimer)
        clearInterval(inactivityTimer);
    inactivityTimer = setInterval(checkInactivity, CHECK_INTERVAL_MS);
}
/**
 * Track activity on a card. Auto-starts a session if needed.
 */
export async function trackActivity(cardId, options) {
    const now = Date.now();
    const existing = activeSessions.get(cardId);
    if (existing) {
        // Update last activity timestamp
        existing.lastActivityAt = now;
        return;
    }
    // Only auto-start if the tool is a trigger
    if (!options?.autoStart)
        return;
    const client = options?.client ?? clientGetter?.();
    if (!client)
        return;
    // Collect auto-sessions on other cards to end (avoid mutating map during iteration)
    const toEnd = [];
    for (const [otherCardId, session] of activeSessions) {
        if (otherCardId !== cardId && !session.isExplicit) {
            toEnd.push(otherCardId);
        }
    }
    for (const otherCardId of toEnd) {
        await autoEndSession(client, otherCardId, "completed");
    }
    // Start a new auto-session
    try {
        await client.startAgentSession(cardId, {
            agentIdentifier: "auto",
            agentName: "Auto-detected Agent",
            status: "working",
        });
    }
    catch {
        // Session start failed (might already have one), still track locally
    }
    activeSessions.set(cardId, {
        cardId,
        startedAt: now,
        lastActivityAt: now,
        isExplicit: false,
        agentIdentifier: "auto",
        agentName: "Auto-detected Agent",
    });
}
/**
 * Mark a session as explicitly started (won't be auto-ended by card switching or inactivity).
 * Optionally accepts the real agent identifier/name to store in the session.
 */
export function markExplicit(cardId, options) {
    const existing = activeSessions.get(cardId);
    if (existing) {
        existing.isExplicit = true;
        if (options?.agentIdentifier)
            existing.agentIdentifier = options.agentIdentifier;
        if (options?.agentName)
            existing.agentName = options.agentName;
    }
    else {
        // Track the explicit session even if we didn't auto-start it
        activeSessions.set(cardId, {
            cardId,
            startedAt: Date.now(),
            lastActivityAt: Date.now(),
            isExplicit: true,
            agentIdentifier: options?.agentIdentifier ?? "explicit",
            agentName: options?.agentName ?? "Explicit Agent",
        });
    }
}
/**
 * Remove a session from tracking (called when session is explicitly ended).
 */
export function untrack(cardId) {
    activeSessions.delete(cardId);
}
/**
 * End all active auto-sessions (called on process shutdown).
 */
export async function shutdownAllSessions() {
    const client = clientGetter?.();
    if (!client)
        return;
    // Snapshot keys to avoid mutating map during iteration
    const cardIds = [...activeSessions.keys()];
    const promises = cardIds.map((cardId) => autoEndSession(client, cardId, "paused"));
    await Promise.allSettled(promises);
}
/**
 * Clean up the interval timer (for tests).
 */
export function destroyAutoSession() {
    if (inactivityTimer) {
        clearInterval(inactivityTimer);
        inactivityTimer = null;
    }
    activeSessions.clear();
    endCallback = null;
    clientGetter = null;
}
/**
 * Get a snapshot of active sessions (for testing/debugging).
 */
export function getActiveSessions() {
    return activeSessions;
}
/**
 * Run inactivity check immediately (exported for testing).
 * In production, called by the setInterval timer every 60s.
 */
export function checkInactivity() {
    const now = Date.now();
    const client = clientGetter?.();
    if (!client)
        return;
    // Snapshot keys to avoid mutating map during iteration
    const entries = [...activeSessions.entries()];
    for (const [cardId, session] of entries) {
        if (session.isExplicit)
            continue;
        if (now - session.lastActivityAt > INACTIVITY_TIMEOUT_MS) {
            autoEndSession(client, cardId, "completed").catch(() => { });
        }
    }
}
// --- Internal ---
async function autoEndSession(client, cardId, status) {
    activeSessions.delete(cardId);
    try {
        await client.endAgentSession(cardId, { status });
    }
    catch {
        // Best-effort end
    }
    try {
        await endCallback?.(client, cardId, status);
    }
    catch {
        // Best-effort pipeline
    }
}
