/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function notifyStateChange(core, state, exitCode) {
    core.callbacks.onStateChange?.({
        state,
        timestamp: Date.now(),
        elapsedMs: Date.now() - core.startMs,
        exitCode,
    });
}
function transitionState(core, newState, exitCode) {
    if (core.state === newState)
        return;
    // eslint-disable-next-line no-param-reassign -- core is a mutable state container by design
    core.state = newState;
    notifyStateChange(core, newState, exitCode);
}
export class ClaudeLifecycleWatcher {
    static IDLE_THRESHOLD_MS = 120_000;
    runtime = 'claude';
    core = { state: 'spawned', startMs: Date.now(), callbacks: {} };
    idleTimer = null;
    lastOutputMs = Date.now();
    start(child, callbacks) {
        this.core.callbacks = callbacks;
        this.core.startMs = Date.now();
        this.lastOutputMs = this.core.startMs;
        notifyStateChange(this.core, 'spawned');
        child.stdout?.on('data', (chunk) => {
            this.lastOutputMs = Date.now();
            if (this.core.state === 'spawned' || this.core.state === 'idle') {
                transitionState(this.core, 'active');
            }
            callbacks.onOutput?.(chunk.toString());
        });
        child.on('close', (code) => {
            this.clearIdleTimer();
            transitionState(this.core, code === 0 ? 'completed' : 'failed', code ?? undefined);
        });
        child.on('error', () => {
            this.clearIdleTimer();
            transitionState(this.core, 'failed');
        });
        this.scheduleIdleCheck();
    }
    getState() {
        return this.core.state;
    }
    getElapsedMs() {
        return Date.now() - this.core.startMs;
    }
    dispose() {
        this.clearIdleTimer();
    }
    scheduleIdleCheck() {
        this.idleTimer = setInterval(() => {
            if (this.core.state !== 'active' && this.core.state !== 'spawned')
                return;
            if (Date.now() - this.lastOutputMs > ClaudeLifecycleWatcher.IDLE_THRESHOLD_MS) {
                transitionState(this.core, 'idle');
            }
        }, 30_000);
    }
    clearIdleTimer() {
        if (this.idleTimer) {
            clearInterval(this.idleTimer);
            this.idleTimer = null;
        }
    }
}
export class CodexLifecycleWatcher {
    runtime = 'codex';
    core = { state: 'spawned', startMs: Date.now(), callbacks: {} };
    start(child, callbacks) {
        this.core.callbacks = callbacks;
        this.core.startMs = Date.now();
        notifyStateChange(this.core, 'spawned');
        child.stdout?.on('data', (chunk) => {
            const text = chunk.toString();
            if (this.core.state === 'spawned') {
                transitionState(this.core, 'active');
            }
            callbacks.onOutput?.(text);
        });
        child.on('close', (code) => {
            transitionState(this.core, code === 0 ? 'completed' : 'failed', code ?? undefined);
        });
        child.on('error', () => {
            transitionState(this.core, 'failed');
        });
    }
    getState() {
        return this.core.state;
    }
    getElapsedMs() {
        return Date.now() - this.core.startMs;
    }
    // eslint-disable-next-line class-methods-use-this
    dispose() {
        // no resources to release in codex watcher
    }
}
export function createLifecycleWatcher(runtime) {
    switch (runtime) {
        case 'claude':
            return new ClaudeLifecycleWatcher();
        default:
            return new CodexLifecycleWatcher();
    }
}
//# sourceMappingURL=lifecycle-watcher.js.map