"use strict";
/**
 * QueueRunner — lifecycle wrapper that turns the autonomous daemon profile
 * "on": it owns a QueueScheduler, wires the real OrchestratedMissionExecutor,
 * and exposes start()/stop() for the Gateway to call.
 *
 * Phase 1 (Daemon Wakeup) of the autonomous-agent milestone.
 *
 * Design note — signal handling lives in the daemon entry (src/index.ts) and
 * Gateway.shutdown(), NOT here. The Gateway calls `queueRunner.stop()` inside
 * its graceful-shutdown path so there is exactly one SIGTERM/SIGINT handler.
 * QueueRunner stays free of process-level side effects, which keeps it
 * unit-testable (inject a scheduler with a mock executor — the heavy
 * orchestration stack is never loaded).
 *
 * Heavy deps (Brain, TaskExecutor, OrchestrationLoop via MissionExecutor) are
 * lazy-required in the constructor's production branch only, matching the
 * repo convention of not paying for the orchestration stack at import time.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueueRunner = void 0;
const QueueScheduler_1 = require("./QueueScheduler");
class QueueRunner {
    scheduler;
    drainTimeoutMs;
    goalTicker;
    started = false;
    constructor(opts = {}) {
        this.drainTimeoutMs = opts.drainTimeoutMs ?? 2500;
        if (opts.scheduler) {
            this.scheduler = opts.scheduler;
            // With an injected scheduler we only attach a ticker if one was
            // explicitly provided (keeps lifecycle tests free of heavy deps).
            this.goalTicker = opts.goalTicker || null;
            return;
        }
        // Production branch: build the real executor. Lazy-require so importing
        // QueueRunner (e.g. in a lifecycle test that injects a scheduler) does
        // not drag the full orchestration stack.
        // eslint-disable-next-line @typescript-eslint/no-var-requires
        const { Brain } = require('./Brain');
        // eslint-disable-next-line @typescript-eslint/no-var-requires
        const { TaskExecutor } = require('./TaskExecutor');
        // eslint-disable-next-line @typescript-eslint/no-var-requires
        const { OrchestratedMissionExecutor } = require('./MissionExecutor');
        const brain = new Brain();
        const executor = new OrchestratedMissionExecutor({
            brain,
            taskExecutor: new TaskExecutor(),
        });
        this.scheduler = new QueueScheduler_1.QueueScheduler({
            executor,
            pollIntervalMs: opts.pollIntervalMs,
            maxConcurrent: opts.maxConcurrent,
        });
        // Phase 2 — goal→mission bridge. On by default; reuses the same Brain.
        if (opts.goalTicker) {
            this.goalTicker = opts.goalTicker;
        }
        else if (opts.enableGoalTicker !== false) {
            // eslint-disable-next-line @typescript-eslint/no-var-requires
            const { GoalTicker } = require('./GoalTicker');
            // eslint-disable-next-line @typescript-eslint/no-var-requires
            const { GoalCompiler } = require('./GoalCompiler');
            this.goalTicker = new GoalTicker({
                compiler: new GoalCompiler({ brain }),
                enqueue: (spec) => this.scheduler.enqueue(spec),
                intervalMs: opts.goalTickIntervalMs,
                onConsentRequired: opts.onConsentRequired,
                onBlocked: opts.onGoalDraftBlocked,
            });
        }
        else {
            this.goalTicker = null;
        }
    }
    /** Start the poll loop + goal ticker. Idempotent. */
    start() {
        if (this.started)
            return;
        this.scheduler.start();
        if (this.goalTicker) {
            this.goalTicker.start();
            console.log('[QUEUE-RUNNER] goal→mission bridge active');
        }
        this.started = true;
        console.log('[QUEUE-RUNNER] autonomous mission polling started');
    }
    /**
     * Stop the ticker + drain in-flight missions (bounded by drainTimeoutMs).
     * Idempotent. Called by Gateway.shutdown() — never registers its own
     * signal handler.
     */
    async stop() {
        if (!this.started)
            return;
        if (this.goalTicker)
            this.goalTicker.stop();
        await this.scheduler.stop({ drain: true, timeoutMs: this.drainTimeoutMs });
        this.started = false;
        console.log('[QUEUE-RUNNER] stopped (drained in-flight missions)');
    }
    /** Enqueue a mission. Thin pass-through to the scheduler. */
    enqueue(spec) {
        return this.scheduler.enqueue(spec);
    }
    /** Inspect the queue. */
    list() {
        return this.scheduler.list();
    }
    isRunning() {
        return this.started;
    }
    /** Exposed for tests + observability. */
    inFlightCount() {
        return this.scheduler.inFlightCount();
    }
}
exports.QueueRunner = QueueRunner;
