import { isTerminalPlanStatus } from '../../types/plan/index.js';
import { generatePlanId } from '../../utils/id.js';
export class PlanManager {
    currentPlan = null;
    runId;
    listeners = [];
    approvalHandler;
    constructor(runId, approvalHandler) {
        this.runId = runId;
        this.approvalHandler = approvalHandler;
    }
    setApprovalHandler(handler) {
        this.approvalHandler = handler;
    }
    on(listener) {
        this.listeners.push(listener);
        return () => {
            this.listeners = this.listeners.filter((l) => l !== listener);
        };
    }
    emit(event) {
        for (const listener of this.listeners) {
            try {
                listener(event);
            }
            catch { }
        }
    }
    get active() {
        return this.currentPlan;
    }
    get isActive() {
        return this.currentPlan !== null && !isTerminalPlanStatus(this.currentPlan.status);
    }
    get needsApproval() {
        return this.currentPlan?.status === 'pending_approval';
    }
    startGenerating(title) {
        const plan = {
            id: generatePlanId(),
            runId: this.runId,
            status: 'generating',
            title,
            steps: [],
            createdAt: Date.now(),
        };
        this.currentPlan = plan;
        this.emit({ type: 'plan.generating', plan });
        return plan;
    }
    addStep(step) {
        if (!this.currentPlan)
            return null;
        if (this.currentPlan.status !== 'generating')
            return null;
        const planStep = {
            ...step,
            status: 'pending',
        };
        this.currentPlan.steps.push(planStep);
        return planStep;
    }
    markReady(summary) {
        if (!this.currentPlan)
            return null;
        if (this.currentPlan.status !== 'generating')
            return null;
        this.currentPlan.status = 'ready';
        this.currentPlan.summary = summary;
        this.currentPlan.readyAt = Date.now();
        this.emit({ type: 'plan.ready', plan: this.currentPlan });
        return this.currentPlan;
    }
    async requestApproval() {
        if (!this.currentPlan) {
            return { approved: false, feedback: 'No active plan' };
        }
        this.currentPlan.status = 'pending_approval';
        if (!this.approvalHandler) {
            this.currentPlan.status = 'rejected';
            this.currentPlan.rejectedAt = Date.now();
            this.currentPlan.rejectionReason = 'No approval handler configured';
            this.emit({ type: 'plan.rejected', plan: this.currentPlan });
            return { approved: false, feedback: 'No approval handler configured' };
        }
        const request = {
            planId: this.currentPlan.id,
            runId: this.runId,
            title: this.currentPlan.title,
            steps: this.currentPlan.steps,
            summary: this.currentPlan.summary,
        };
        const response = await this.approvalHandler(request);
        if (response.approved) {
            if (response.modifiedSteps) {
                this.currentPlan.steps = response.modifiedSteps;
            }
            this.currentPlan.status = 'approved';
            this.currentPlan.approvedAt = Date.now();
            this.emit({ type: 'plan.approved', plan: this.currentPlan });
        }
        else {
            this.currentPlan.status = 'rejected';
            this.currentPlan.rejectedAt = Date.now();
            this.currentPlan.rejectionReason = response.feedback;
            this.emit({ type: 'plan.rejected', plan: this.currentPlan });
        }
        return response;
    }
    approve(modifiedSteps) {
        if (!this.currentPlan)
            return null;
        if (this.currentPlan.status !== 'pending_approval' && this.currentPlan.status !== 'ready')
            return null;
        if (modifiedSteps) {
            this.currentPlan.steps = modifiedSteps;
        }
        this.currentPlan.status = 'approved';
        this.currentPlan.approvedAt = Date.now();
        this.emit({ type: 'plan.approved', plan: this.currentPlan });
        return this.currentPlan;
    }
    startExecution() {
        if (!this.currentPlan)
            return null;
        if (this.currentPlan.status !== 'approved')
            return null;
        this.currentPlan.status = 'executing';
        this.emit({ type: 'plan.executing', plan: this.currentPlan });
        return this.currentPlan;
    }
    updateStepStatus(stepId, status, error) {
        if (!this.currentPlan)
            return null;
        const step = this.currentPlan.steps.find((s) => s.id === stepId);
        if (!step)
            return null;
        step.status = status;
        if (error)
            step.error = error;
        this.emit({ type: 'plan.step_updated', plan: this.currentPlan, step });
        return step;
    }
    completePlan() {
        if (!this.currentPlan)
            return null;
        const allDone = this.currentPlan.steps.every((s) => s.status === 'completed' || s.status === 'skipped');
        this.currentPlan.status = allDone ? 'completed' : 'failed';
        this.currentPlan.completedAt = Date.now();
        this.emit({
            type: allDone ? 'plan.completed' : 'plan.failed',
            plan: this.currentPlan,
        });
        return this.currentPlan;
    }
    failPlan(_error) {
        if (!this.currentPlan)
            return null;
        this.currentPlan.status = 'failed';
        this.currentPlan.completedAt = Date.now();
        for (const step of this.currentPlan.steps) {
            if (step.status === 'pending' || step.status === 'running') {
                step.status = 'skipped';
            }
        }
        this.emit({ type: 'plan.failed', plan: this.currentPlan });
        return this.currentPlan;
    }
    getNextPendingStep() {
        if (!this.currentPlan)
            return null;
        if (this.currentPlan.status !== 'executing')
            return null;
        for (const step of this.currentPlan.steps) {
            if (step.status !== 'pending')
                continue;
            const depsResolved = step.dependsOn.every((depId) => {
                const dep = this.currentPlan?.steps.find((s) => s.id === depId);
                return dep && (dep.status === 'completed' || dep.status === 'skipped');
            });
            if (depsResolved)
                return step;
        }
        return null;
    }
    reset() {
        this.currentPlan = null;
    }
}
//# sourceMappingURL=lifecycle.js.map