"use strict";
/**
 * Job Executor
 * Issue #479: Extracted from schedule-manager.ts for single responsibility
 *
 * Handles execution of scheduled tasks and execution log management.
 * This module manages the DB logging lifecycle (create/update execution logs)
 * and delegates actual command execution to claude-executor.
 *
 * Trust boundary: All inputs are DB-derived from schedule-manager.ts (trusted).
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.createExecutionLog = createExecutionLog;
exports.updateExecutionLog = updateExecutionLog;
exports.updateScheduleLastExecuted = updateScheduleLastExecuted;
exports.recoverRunningLogs = recoverRunningLogs;
exports.executeSchedule = executeSchedule;
const crypto_1 = require("crypto");
const claude_executor_1 = require("./session/claude-executor");
const logger_1 = require("../lib/logger");
const logger = (0, logger_1.createLogger)('job-executor');
// =============================================================================
// Lazy DB Accessor
// =============================================================================
/**
 * Lazy-load the DB instance to avoid circular import issues.
 * Duplicated from schedule-manager.ts to avoid circular dependency.
 *
 * @returns The SQLite database instance
 */
function getLazyDbInstance() {
    // eslint-disable-next-line @typescript-eslint/no-require-imports
    const { getDbInstance } = require('./db-instance');
    return getDbInstance();
}
// =============================================================================
// DB Operations - Execution Logs
// =============================================================================
/**
 * Create an execution log entry in 'running' status.
 *
 * @param scheduleId - The parent schedule ID
 * @param worktreeId - The worktree ID
 * @param message - The execution message/prompt
 * @returns The new execution log ID
 */
function createExecutionLog(scheduleId, worktreeId, message) {
    const db = getLazyDbInstance();
    const now = Date.now();
    const id = (0, crypto_1.randomUUID)();
    db.prepare(`
    INSERT INTO execution_logs (id, schedule_id, worktree_id, message, status, started_at, created_at)
    VALUES (?, ?, ?, ?, 'running', ?, ?)
  `).run(id, scheduleId, worktreeId, message, now, now);
    return id;
}
/**
 * Update an execution log entry with results.
 *
 * @param logId - The execution log ID to update
 * @param status - The final execution status
 * @param result - The execution output or error message
 * @param exitCode - The process exit code, or null if unknown
 */
function updateExecutionLog(logId, status, result, exitCode) {
    const db = getLazyDbInstance();
    const now = Date.now();
    db.prepare(`
    UPDATE execution_logs SET status = ?, result = ?, exit_code = ?, completed_at = ? WHERE id = ?
  `).run(status, result, exitCode, now, logId);
}
/**
 * Update the last_executed_at timestamp for a schedule.
 *
 * @param scheduleId - The schedule ID to update
 */
function updateScheduleLastExecuted(scheduleId) {
    const db = getLazyDbInstance();
    const now = Date.now();
    db.prepare('UPDATE scheduled_executions SET last_executed_at = ?, updated_at = ? WHERE id = ?')
        .run(now, now, scheduleId);
}
/**
 * Recovery: mark all 'running' execution logs as 'failed' on startup.
 * This handles the case where the server was killed while executions
 * were still in progress.
 */
function recoverRunningLogs() {
    try {
        const db = getLazyDbInstance();
        const now = Date.now();
        const result = db.prepare("UPDATE execution_logs SET status = 'failed', completed_at = ? WHERE status = 'running'").run(now);
        if (result.changes > 0) {
            logger.warn('execution:recovered-stale', { count: result.changes });
        }
    }
    catch (error) {
        logger.error('execution:recover-failed', { error: error instanceof Error ? error.message : String(error) });
    }
}
// =============================================================================
// Schedule Execution
// =============================================================================
/**
 * Execute a scheduled task.
 * Guards against concurrent execution of the same schedule.
 *
 * @param state - The schedule state to execute
 */
async function executeSchedule(state) {
    if (state.isExecuting) {
        logger.warn('execution:skip-concurrent', { name: state.entry.name });
        return;
    }
    state.isExecuting = true;
    const logId = createExecutionLog(state.scheduleId, state.worktreeId, state.entry.message);
    try {
        const db = getLazyDbInstance();
        const worktree = db.prepare('SELECT path, vibe_local_model FROM worktrees WHERE id = ?').get(state.worktreeId);
        if (!worktree) {
            updateExecutionLog(logId, 'failed', 'Worktree not found', null);
            return;
        }
        // Build options for vibe-local model
        const options = state.entry.cliToolId === 'vibe-local' && worktree.vibe_local_model
            ? { model: worktree.vibe_local_model }
            : undefined;
        const result = await (0, claude_executor_1.executeClaudeCommand)(state.entry.message, worktree.path, state.entry.cliToolId, state.entry.permission, options);
        updateExecutionLog(logId, result.status, result.output, result.exitCode);
        updateScheduleLastExecuted(state.scheduleId);
        logger.info('execution:completed', { name: state.entry.name, status: result.status });
    }
    catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        updateExecutionLog(logId, 'failed', errorMessage, null);
        logger.error('execution:failed', { name: state.entry.name, error: errorMessage });
    }
    finally {
        state.isExecuting = false;
    }
}
