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 { ClearSurvival } from "../session/clear-survival.js";
import { HandoffGenerator } from "../session/handoff-generator.js";
import * as fs from "fs/promises";
import * as path from "path";
class SessionMonitor extends EventEmitter {
  config;
  clearSurvival;
  handoffGenerator;
  frameManager;
  dbManager;
  monitorInterval;
  lastActivityTime;
  isMonitoring = false;
  projectRoot;
  // Track context state to avoid duplicate saves
  lastContextCheck = { tokens: 0, percentage: 0 };
  constructor(frameManager, dbManager, projectRoot, config) {
    super();
    this.frameManager = frameManager;
    this.dbManager = dbManager;
    this.projectRoot = projectRoot;
    this.lastActivityTime = /* @__PURE__ */ new Date();
    this.config = {
      contextWarningThreshold: 0.6,
      contextCriticalThreshold: 0.7,
      contextAutoSaveThreshold: 0.85,
      idleTimeoutMinutes: 5,
      sessionEndHandoff: true,
      checkIntervalSeconds: 30,
      autoSaveLedger: true,
      autoGenerateHandoff: true,
      autoCompactOnThreshold: false,
      ...config
    };
    this.clearSurvival = new ClearSurvival(
      frameManager,
      dbManager,
      new HandoffGenerator(frameManager, dbManager, projectRoot),
      projectRoot
    );
    this.handoffGenerator = new HandoffGenerator(
      frameManager,
      dbManager,
      projectRoot
    );
  }
  /**
   * Start monitoring session
   */
  async start() {
    if (this.isMonitoring) return;
    this.isMonitoring = true;
    this.lastActivityTime = /* @__PURE__ */ new Date();
    this.monitorInterval = setInterval(
      () => this.checkSession(),
      this.config.checkIntervalSeconds * 1e3
    );
    this.registerExitHandlers();
    this.emit("monitor:started");
    console.log("\u{1F50D} Session monitor started");
  }
  /**
   * Stop monitoring
   */
  async stop() {
    if (!this.isMonitoring) return;
    this.isMonitoring = false;
    if (this.monitorInterval) {
      clearInterval(this.monitorInterval);
      this.monitorInterval = void 0;
    }
    if (this.config.sessionEndHandoff) {
      await this.generateHandoff("session_end");
    }
    this.emit("monitor:stopped");
    console.log("\u{1F6D1} Session monitor stopped");
  }
  /**
   * Main monitoring check
   */
  async checkSession() {
    try {
      await this.checkContextUsage();
      await this.checkIdleTimeout();
      await this.checkCustomTriggers();
    } catch (error) {
      console.error("Monitor check failed:", error);
      this.emit("monitor:error", error);
    }
  }
  /**
   * Check context usage and trigger actions
   */
  async checkContextUsage() {
    const currentTokens = await this.estimateTokens();
    const maxTokens = 1e5;
    const percentage = currentTokens / maxTokens;
    this.lastContextCheck = {
      tokens: currentTokens,
      percentage,
      savedAt: this.lastContextCheck.savedAt
    };
    this.emit("context:usage", {
      tokens: currentTokens,
      maxTokens,
      percentage,
      status: this.getContextStatus(percentage)
    });
    if (percentage >= this.config.contextAutoSaveThreshold) {
      await this.handleCriticalContext();
    } else if (percentage >= this.config.contextCriticalThreshold) {
      await this.handleHighContext();
    } else if (percentage >= this.config.contextWarningThreshold) {
      this.handleWarningContext();
    }
  }
  /**
   * Handle critical context (>85%)
   */
  async handleCriticalContext() {
    if (this.lastContextCheck.savedAt) {
      const minsSinceLastSave = (Date.now() - this.lastContextCheck.savedAt.getTime()) / 6e4;
      if (minsSinceLastSave < 5) return;
    }
    console.log("\u{1F534} Critical context usage - auto-saving ledger");
    if (this.config.autoSaveLedger) {
      const ledger = await this.clearSurvival.saveContinuityLedger();
      this.lastContextCheck.savedAt = /* @__PURE__ */ new Date();
      this.emit("context:ledger_saved", {
        compression: ledger.compression_ratio,
        frames: ledger.active_frame_stack.length,
        tasks: ledger.active_tasks.length
      });
      console.log("\u{1F4A1} Ledger saved. Run /clear to reset context");
      if (this.config.autoCompactOnThreshold) {
        this.emit("context:suggest_clear");
      }
    }
  }
  /**
   * Handle high context (70-85%)
   */
  async handleHighContext() {
    console.log("\u26A0\uFE0F High context usage - consider saving ledger");
    this.emit("context:high", {
      percentage: this.lastContextCheck.percentage,
      suggestion: "Run: stackmemory clear --save"
    });
  }
  /**
   * Handle warning context (60-70%)
   */
  handleWarningContext() {
    this.emit("context:warning", {
      percentage: this.lastContextCheck.percentage
    });
  }
  /**
   * Check for idle timeout
   */
  async checkIdleTimeout() {
    const idleMinutes = (Date.now() - this.lastActivityTime.getTime()) / 6e4;
    if (idleMinutes >= this.config.idleTimeoutMinutes) {
      if (this.config.autoGenerateHandoff) {
        await this.generateHandoff("idle_timeout");
      }
    }
  }
  /**
   * Generate handoff document
   */
  async generateHandoff(trigger) {
    try {
      const sessionId = await this.dbManager.getCurrentSessionId();
      const handoff = await this.handoffGenerator.generateHandoff(sessionId);
      this.emit("handoff:generated", {
        trigger,
        sessionDuration: handoff.session_duration_minutes,
        tasksActive: handoff.active_tasks.filter(
          (t) => t.status !== "completed"
        ).length
      });
      console.log(`\u{1F4CB} Handoff generated (trigger: ${trigger})`);
    } catch (error) {
      console.error("Failed to generate handoff:", error);
    }
  }
  /**
   * Register process exit handlers
   */
  registerExitHandlers() {
    const exitHandler = async (signal) => {
      console.log(`
\u{1F4E6} Received ${signal}, saving session state...`);
      try {
        if (this.lastContextCheck.percentage > 0.3) {
          await this.clearSurvival.saveContinuityLedger();
          console.log("\u2705 Continuity ledger saved");
        }
        if (this.config.sessionEndHandoff) {
          await this.generateHandoff("process_exit");
          console.log("\u2705 Handoff document generated");
        }
      } catch (error) {
        console.error("Error during exit handling:", error);
      } finally {
        process.exit(0);
      }
    };
    process.once("SIGINT", () => exitHandler("SIGINT"));
    process.once("SIGTERM", () => exitHandler("SIGTERM"));
    process.once("beforeExit", () => exitHandler("beforeExit"));
  }
  /**
   * Update last activity time
   */
  updateActivity() {
    this.lastActivityTime = /* @__PURE__ */ new Date();
  }
  /**
   * Check custom triggers (extensible)
   */
  async checkCustomTriggers() {
    const hooksDir = path.join(this.projectRoot, ".stackmemory", "hooks");
    try {
      await fs.access(hooksDir);
      const hooks = await fs.readdir(hooksDir);
      for (const hook of hooks) {
        if (hook.startsWith("monitor_") && hook.endsWith(".js")) {
          try {
            const hookPath = path.join(hooksDir, hook);
            const hookModule = await import(hookPath);
            if (hookModule.check) {
              const shouldTrigger = await hookModule.check({
                contextPercentage: this.lastContextCheck.percentage,
                idleMinutes: (Date.now() - this.lastActivityTime.getTime()) / 6e4,
                frameCount: (await this.frameManager.getStack()).frames.length
              });
              if (shouldTrigger && hookModule.action) {
                await hookModule.action({
                  clearSurvival: this.clearSurvival,
                  handoffGenerator: this.handoffGenerator,
                  frameManager: this.frameManager
                });
              }
            }
          } catch (error) {
            console.error(`Hook ${hook} failed:`, error);
          }
        }
      }
    } catch {
    }
  }
  /**
   * Estimate current token usage
   */
  async estimateTokens() {
    const sessionId = await this.dbManager.getCurrentSessionId();
    const frames = await this.dbManager.getRecentFrames(sessionId, 100);
    const traces = await this.dbManager.getRecentTraces(sessionId, 100);
    return frames.length * 200 + traces.length * 100;
  }
  /**
   * Get context status based on percentage
   */
  getContextStatus(percentage) {
    if (percentage >= this.config.contextAutoSaveThreshold) return "critical";
    if (percentage >= this.config.contextCriticalThreshold) return "high";
    if (percentage >= this.config.contextWarningThreshold) return "warning";
    return "ok";
  }
  /**
   * Get current monitor status
   */
  getStatus() {
    return {
      isMonitoring: this.isMonitoring,
      lastActivity: this.lastActivityTime,
      contextUsage: this.lastContextCheck,
      config: this.config
    };
  }
  /**
   * Update configuration
   */
  updateConfig(config) {
    this.config = { ...this.config, ...config };
    this.emit("config:updated", this.config);
  }
}
export {
  SessionMonitor
};
//# sourceMappingURL=session-monitor.js.map
