"use strict";
/**
 * Session Key Sender - tmux key sending wrappers for Claude CLI sessions.
 *
 * Extracted from claude-session.ts (Issue #479) to separate key-sending
 * control logic from session lifecycle management.
 *
 * Dependencies: tmux.ts (sendKeys, sendSpecialKey) - one-way dependency.
 * claude-session.ts -> session-key-sender.ts -> tmux.ts
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.sanitizeSessionEnvironment = sanitizeSessionEnvironment;
exports.waitForPrompt = waitForPrompt;
exports.sendMessageToSession = sendMessageToSession;
exports.stopSession = stopSession;
const tmux_1 = require("./tmux/tmux");
const cli_patterns_1 = require("./detection/cli-patterns");
const pasted_text_helper_1 = require("./pasted-text-helper");
const tmux_capture_cache_1 = require("./tmux/tmux-capture-cache");
const errors_1 = require("./errors");
const child_process_1 = require("child_process");
const util_1 = require("util");
const logger_1 = require("../lib/logger");
const logger = (0, logger_1.createLogger)('session-key-sender');
const execAsync = (0, util_1.promisify)(child_process_1.exec);
/**
 * Capture tmux pane output and strip ANSI escape sequences
 *
 * @param sessionName - tmux session name
 * @param lines - Number of lines to capture (default: 50)
 * @returns Clean pane output with ANSI codes removed
 */
async function getCleanPaneOutput(sessionName, lines = 50) {
    const output = await (0, tmux_1.capturePane)(sessionName, { startLine: -lines });
    return (0, cli_patterns_1.stripAnsi)(output);
}
// =============================================================================
// Constants (duplicated from claude-session.ts for one-way dependency)
// =============================================================================
/**
 * Prompt wait polling interval (milliseconds)
 */
const PROMPT_POLL_INTERVAL = 200;
// =============================================================================
// Environment Sanitization
// =============================================================================
/**
 * Remove CLAUDECODE environment variable from tmux session environment
 * Prevents Claude Code from detecting nested session and refusing to start
 * (SF-002: SRP - environment sanitization separated from session creation)
 *
 * MF-S3-002: tmux set-environment -g -u operates on the global tmux environment.
 *
 * SEC-SF-001: sessionName is validated by the caller chain:
 * ClaudeTool.startSession() -> BaseCLITool.getSessionName() -> validateSessionName()
 *
 * @param sessionName - tmux session name
 */
async function sanitizeSessionEnvironment(sessionName) {
    // 3-1: Remove from tmux global environment
    await execAsync('tmux set-environment -g -u CLAUDECODE 2>/dev/null || true');
    // 3-2: Unset inside the session shell (safety net)
    // 100ms wait: empirically determined time for sendKeys command to reach the shell
    await (0, tmux_1.sendKeys)(sessionName, 'unset CLAUDECODE', true);
    await new Promise(resolve => setTimeout(resolve, 100));
}
// =============================================================================
// Prompt Wait
// =============================================================================
/**
 * Wait for session to be at prompt state
 * Polls for prompt detection using CLAUDE_PROMPT_PATTERN (DRY-001)
 *
 * @param sessionName - tmux session name
 * @param timeout - Timeout in milliseconds
 * @throws {Error} If prompt is not detected within timeout
 */
async function waitForPrompt(sessionName, timeout) {
    const startTime = Date.now();
    while (Date.now() - startTime < timeout) {
        const cleanOutput = await getCleanPaneOutput(sessionName);
        if (cli_patterns_1.CLAUDE_PROMPT_PATTERN.test(cleanOutput)) {
            return; // Prompt detected
        }
        await new Promise((resolve) => setTimeout(resolve, PROMPT_POLL_INTERVAL));
    }
    throw new Error(`Prompt detection timeout (${timeout}ms)`);
}
// =============================================================================
// Message Sending
// =============================================================================
/**
 * Send a message to Claude CLI
 *
 * @param sessionName - tmux session name
 * @param message - Message content to send
 * @param postPromptDelay - Stability delay after prompt detection (ms)
 * @param promptWaitTimeout - Timeout for waiting for prompt state (ms)
 * @throws {Error} If session doesn't exist
 */
async function sendMessageToSession(sessionName, message, postPromptDelay, promptWaitTimeout) {
    // Check if session exists
    const exists = await (0, tmux_1.hasSession)(sessionName);
    if (!exists) {
        throw new Error(`Claude session ${sessionName} does not exist. Start the session first.`);
    }
    // Verify prompt state before sending
    const cleanOutput = await getCleanPaneOutput(sessionName);
    if (!cli_patterns_1.CLAUDE_PROMPT_PATTERN.test(cleanOutput)) {
        await waitForPrompt(sessionName, promptWaitTimeout);
    }
    // Stability delay after prompt detection
    await new Promise((resolve) => setTimeout(resolve, postPromptDelay));
    // Send message using sendKeys consistently (CONS-001)
    await (0, tmux_1.sendKeys)(sessionName, message, false);
    await (0, tmux_1.sendKeys)(sessionName, '', true);
    // Issue #212: Detect [Pasted text] and resend Enter for multi-line messages
    // MF-001: Single-line messages skip detection (+0ms overhead)
    if (message.includes('\n')) {
        await (0, pasted_text_helper_1.detectAndResendIfPastedText)(sessionName);
    }
    // Issue #405: Invalidate cache after sending message
    (0, tmux_capture_cache_1.invalidateCache)(sessionName);
    logger.info('sent-message-to-session', { sessionName });
}
// =============================================================================
// Session Stop
// =============================================================================
/**
 * Stop a Claude session by sending Ctrl+D and killing the tmux session.
 *
 * @param sessionName - tmux session name
 * @returns True if session was stopped, false if it didn't exist or error occurred
 */
async function stopSession(sessionName) {
    try {
        // Send Ctrl+D to exit Claude gracefully
        const exists = await (0, tmux_1.hasSession)(sessionName);
        if (exists) {
            await (0, tmux_1.sendKeys)(sessionName, '', false);
            // Send Ctrl+D (ASCII 4)
            await (0, tmux_1.sendSpecialKey)(sessionName, 'C-d');
            // Issue #405: Invalidate cache after sending stop signal
            (0, tmux_capture_cache_1.invalidateCache)(sessionName);
            // Wait a moment for Claude to exit
            await new Promise((resolve) => setTimeout(resolve, 500));
        }
        // Kill the tmux session
        const killed = await (0, tmux_1.killSession)(sessionName);
        if (killed) {
            logger.info('stopped-session', { sessionName });
        }
        return killed;
    }
    catch (error) {
        logger.error('session:stop-failed', { error: (0, errors_1.getErrorMessage)(error) });
        return false;
    }
}
