import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { EventEmitter } from "events";
import { execSync } from "child_process";
import { logger } from "../../../core/monitoring/logger.js";
class IterationLifecycle extends EventEmitter {
  config;
  hooks = {};
  checkpoints = [];
  currentIteration;
  iterationHistory = [];
  activeTimers = /* @__PURE__ */ new Map();
  constructor(config, hooks) {
    super();
    this.config = {
      hooks: {
        preIteration: config?.hooks?.preIteration ?? true,
        postIteration: config?.hooks?.postIteration ?? true,
        onStateChange: config?.hooks?.onStateChange ?? true,
        onError: config?.hooks?.onError ?? true,
        onComplete: config?.hooks?.onComplete ?? true
      },
      checkpoints: {
        enabled: config?.checkpoints?.enabled ?? true,
        frequency: config?.checkpoints?.frequency || 5,
        retentionDays: config?.checkpoints?.retentionDays || 7
      }
    };
    if (hooks) {
      this.registerHooks(hooks);
    }
    this.setupEventHandlers();
  }
  /**
   * Register lifecycle hooks
   */
  registerHooks(hooks) {
    this.hooks = { ...this.hooks, ...hooks };
    logger.debug("Lifecycle hooks registered", {
      registered: Object.keys(hooks)
    });
  }
  /**
   * Start iteration with lifecycle management
   */
  async startIteration(iterationNumber, context) {
    logger.info("Starting iteration", { iteration: iterationNumber });
    this.emitEvent({
      type: "iteration.started",
      timestamp: Date.now(),
      iteration: iterationNumber,
      data: { context }
    });
    let processedContext = context;
    if (this.config.hooks.preIteration && this.hooks.preIteration) {
      try {
        processedContext = await this.hooks.preIteration(context);
        logger.debug("Pre-iteration hook executed", {
          original: context.tokenCount,
          processed: processedContext.tokenCount
        });
      } catch (error) {
        await this.handleError(error, { phase: "preIteration", context });
      }
    }
    this.startTimer(`iteration-${iterationNumber}`);
    return processedContext;
  }
  /**
   * Complete iteration with lifecycle management
   */
  async completeIteration(iteration) {
    logger.info("Completing iteration", { iteration: iteration.number });
    this.currentIteration = iteration;
    const duration = this.stopTimer(`iteration-${iteration.number}`);
    if (this.config.hooks.postIteration && this.hooks.postIteration) {
      try {
        await this.hooks.postIteration(iteration);
        logger.debug("Post-iteration hook executed");
      } catch (error) {
        await this.handleError(error, { phase: "postIteration", iteration });
      }
    }
    if (this.shouldCreateCheckpoint(iteration.number)) {
      await this.createCheckpoint(iteration);
    }
    this.emitEvent({
      type: "iteration.completed",
      timestamp: Date.now(),
      iteration: iteration.number,
      data: {
        iteration,
        duration,
        success: iteration.validation.testsPass
      }
    });
    await this.cleanOldCheckpoints();
  }
  /**
   * Handle iteration failure
   */
  async failIteration(iterationNumber, error, context) {
    logger.error("Iteration failed", {
      iteration: iterationNumber,
      error: error.message
    });
    this.stopTimer(`iteration-${iterationNumber}`);
    if (this.config.hooks.onError && this.hooks.onError) {
      try {
        await this.hooks.onError(error, context);
      } catch (hookError) {
        logger.error("Error hook failed", { error: hookError.message });
      }
    }
    this.emitEvent({
      type: "iteration.failed",
      timestamp: Date.now(),
      iteration: iterationNumber,
      data: {
        error: error.message,
        stack: error.stack,
        context
      }
    });
  }
  /**
   * Handle state change
   */
  async handleStateChange(oldState, newState) {
    logger.debug("State change detected", {
      old: oldState.status,
      new: newState.status,
      iteration: newState.iteration
    });
    if (this.config.hooks.onStateChange && this.hooks.onStateChange) {
      try {
        await this.hooks.onStateChange(oldState, newState);
      } catch (error) {
        await this.handleError(error, {
          phase: "stateChange",
          oldState,
          newState
        });
      }
    }
    this.emitEvent({
      type: "state.changed",
      timestamp: Date.now(),
      iteration: newState.iteration,
      data: {
        oldStatus: oldState.status,
        newStatus: newState.status,
        changes: this.detectStateChanges(oldState, newState)
      }
    });
    if (newState.status === "completed" && oldState.status !== "completed") {
      await this.handleCompletion(newState);
    }
  }
  /**
   * Handle loop completion
   */
  async handleCompletion(state) {
    logger.info("Loop completed", {
      iterations: state.iteration,
      duration: state.lastUpdateTime - state.startTime
    });
    if (this.config.hooks.onComplete && this.hooks.onComplete) {
      try {
        await this.hooks.onComplete(state);
      } catch (error) {
        await this.handleError(error, { phase: "completion", state });
      }
    }
    await this.createFinalCheckpoint(state);
    this.cleanupTimers();
  }
  /**
   * Create checkpoint
   */
  async createCheckpoint(iteration) {
    const checkpoint = {
      id: this.generateCheckpointId(),
      iteration: iteration.number,
      timestamp: Date.now(),
      state: await this.captureCurrentState(),
      gitCommit: await this.getCurrentGitCommit(),
      verified: false
    };
    checkpoint.verified = await this.verifyCheckpoint(checkpoint);
    this.checkpoints.push(checkpoint);
    logger.info("Checkpoint created", {
      id: checkpoint.id,
      iteration: checkpoint.iteration,
      verified: checkpoint.verified
    });
    if (this.hooks.onCheckpoint) {
      try {
        await this.hooks.onCheckpoint(checkpoint);
      } catch (error) {
        logger.error("Checkpoint hook failed", { error: error.message });
      }
    }
    this.emitEvent({
      type: "checkpoint.created",
      timestamp: Date.now(),
      iteration: iteration.number,
      data: { checkpoint }
    });
    return checkpoint;
  }
  /**
   * Get checkpoints
   */
  getCheckpoints() {
    return [...this.checkpoints];
  }
  /**
   * Get last checkpoint
   */
  getLastCheckpoint() {
    return this.checkpoints[this.checkpoints.length - 1];
  }
  /**
   * Restore from checkpoint
   */
  async restoreFromCheckpoint(checkpointId) {
    const checkpoint = this.checkpoints.find((c) => c.id === checkpointId);
    if (!checkpoint) {
      throw new Error(`Checkpoint not found: ${checkpointId}`);
    }
    logger.info("Restoring from checkpoint", {
      id: checkpoint.id,
      iteration: checkpoint.iteration
    });
    if (checkpoint.gitCommit) {
      await this.restoreGitState(checkpoint.gitCommit);
    }
    await this.restoreRalphState(checkpoint.state);
    logger.info("Checkpoint restored successfully");
  }
  /**
   * Get iteration events
   */
  getEvents(filter) {
    let events = [...this.iterationHistory];
    if (filter?.type) {
      events = events.filter((e) => e.type === filter.type);
    }
    if (filter?.iteration !== void 0) {
      events = events.filter((e) => e.iteration === filter.iteration);
    }
    if (filter?.since) {
      events = events.filter((e) => e.timestamp >= filter.since);
    }
    return events;
  }
  /**
   * Clean up resources
   */
  cleanup() {
    this.cleanupTimers();
    this.removeAllListeners();
    this.iterationHistory = [];
    this.checkpoints = [];
  }
  /**
   * Setup internal event handlers
   */
  setupEventHandlers() {
    this.on("*", (event) => {
      logger.debug("Lifecycle event", {
        type: event.type,
        iteration: event.iteration
      });
    });
  }
  /**
   * Emit and track event
   */
  emitEvent(event) {
    this.iterationHistory.push(event);
    this.emit(event.type, event);
    this.emit("*", event);
  }
  /**
   * Should create checkpoint based on frequency
   */
  shouldCreateCheckpoint(iteration) {
    if (!this.config.checkpoints.enabled) {
      return false;
    }
    return iteration % this.config.checkpoints.frequency === 0;
  }
  /**
   * Generate checkpoint ID
   */
  generateCheckpointId() {
    return `chk-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
  }
  /**
   * Capture current state
   */
  async captureCurrentState() {
    return {
      loopId: "current",
      task: "",
      criteria: "",
      iteration: this.currentIteration?.number || 0,
      status: "running",
      startTime: Date.now(),
      lastUpdateTime: Date.now()
    };
  }
  /**
   * Get current git commit
   */
  async getCurrentGitCommit() {
    try {
      return execSync("git rev-parse HEAD", { encoding: "utf8" }).trim();
    } catch {
      return "";
    }
  }
  /**
   * Verify checkpoint integrity
   */
  async verifyCheckpoint(checkpoint) {
    try {
      if (!checkpoint.state.loopId || !checkpoint.state.task) {
        return false;
      }
      if (checkpoint.gitCommit) {
        execSync(`git rev-parse ${checkpoint.gitCommit}`, { encoding: "utf8" });
      }
      return true;
    } catch {
      return false;
    }
  }
  /**
   * Clean old checkpoints based on retention
   */
  async cleanOldCheckpoints() {
    const cutoff = Date.now() - this.config.checkpoints.retentionDays * 24 * 60 * 60 * 1e3;
    const before = this.checkpoints.length;
    this.checkpoints = this.checkpoints.filter((c) => c.timestamp >= cutoff);
    const removed = before - this.checkpoints.length;
    if (removed > 0) {
      logger.debug("Cleaned old checkpoints", { removed });
    }
  }
  /**
   * Create final checkpoint
   */
  async createFinalCheckpoint(state) {
    const checkpoint = {
      id: `final-${this.generateCheckpointId()}`,
      iteration: state.iteration,
      timestamp: Date.now(),
      state,
      gitCommit: await this.getCurrentGitCommit(),
      verified: true
    };
    this.checkpoints.push(checkpoint);
    logger.info("Final checkpoint created", {
      id: checkpoint.id,
      iterations: state.iteration
    });
  }
  /**
   * Restore git state
   */
  async restoreGitState(commit) {
    execSync("git stash", { encoding: "utf8" });
    execSync(`git checkout ${commit}`, { encoding: "utf8" });
  }
  /**
   * Restore Ralph state
   */
  async restoreRalphState(state) {
    logger.debug("Ralph state restored", { iteration: state.iteration });
  }
  /**
   * Detect state changes
   */
  detectStateChanges(oldState, newState) {
    const changes = [];
    for (const key of Object.keys(newState)) {
      if (JSON.stringify(oldState[key]) !== JSON.stringify(newState[key])) {
        changes.push(key);
      }
    }
    return changes;
  }
  /**
   * Handle errors
   */
  async handleError(error, context) {
    logger.error("Lifecycle error", {
      error: error.message,
      context
    });
    if (this.config.hooks.onError && this.hooks.onError) {
      try {
        await this.hooks.onError(error, context);
      } catch (hookError) {
        logger.error("Error hook failed", { error: hookError.message });
      }
    }
  }
  /**
   * Start timer for metrics
   */
  startTimer(name) {
    const start = Date.now();
    this.activeTimers.set(name, setTimeout(() => {
      this.activeTimers.delete(name);
    }, 0));
    this.activeTimers.get(name).startTime = start;
  }
  /**
   * Stop timer and get duration
   */
  stopTimer(name) {
    const timer = this.activeTimers.get(name);
    if (!timer) return 0;
    const duration = Date.now() - timer.startTime;
    clearTimeout(timer);
    this.activeTimers.delete(name);
    return duration;
  }
  /**
   * Clean up all timers
   */
  cleanupTimers() {
    for (const timer of this.activeTimers.values()) {
      clearTimeout(timer);
    }
    this.activeTimers.clear();
  }
}
export {
  IterationLifecycle
};
//# sourceMappingURL=iteration-lifecycle.js.map
