#!/usr/bin/env node
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import {
  existsSync,
  writeFileSync,
  unlinkSync,
  appendFileSync,
  readFileSync
} from "fs";
import {
  loadDaemonConfig,
  getDaemonPaths,
  writeDaemonStatus
} from "./daemon-config.js";
import { DaemonContextService } from "./services/context-service.js";
import { DaemonLinearService } from "./services/linear-service.js";
class UnifiedDaemon {
  config;
  paths;
  contextService;
  linearService;
  heartbeatInterval;
  isShuttingDown = false;
  startTime = 0;
  constructor(config) {
    this.paths = getDaemonPaths();
    this.config = { ...loadDaemonConfig(), ...config };
    this.contextService = new DaemonContextService(
      this.config.context,
      (level, msg, data) => this.log(level, "context", msg, data)
    );
    this.linearService = new DaemonLinearService(
      this.config.linear,
      (level, msg, data) => this.log(level, "linear", msg, data)
    );
  }
  log(level, service, message, data) {
    const logLevel = level.toUpperCase();
    const levels = ["DEBUG", "INFO", "WARN", "ERROR"];
    const configLevel = this.config.logLevel.toUpperCase();
    if (levels.indexOf(logLevel) < levels.indexOf(configLevel)) {
      return;
    }
    const entry = {
      timestamp: (/* @__PURE__ */ new Date()).toISOString(),
      level: logLevel,
      service,
      message,
      data
    };
    const logLine = JSON.stringify(entry) + "\n";
    try {
      appendFileSync(this.paths.logFile, logLine);
    } catch {
      console.error(`[${entry.timestamp}] ${level} [${service}]: ${message}`);
    }
  }
  checkIdempotency() {
    if (existsSync(this.paths.pidFile)) {
      try {
        const existingPid = readFileSync(this.paths.pidFile, "utf8").trim();
        const pid = parseInt(existingPid, 10);
        try {
          process.kill(pid, 0);
          this.log("WARN", "daemon", "Daemon already running", { pid });
          return false;
        } catch {
          this.log("INFO", "daemon", "Cleaning stale PID file", { pid });
          unlinkSync(this.paths.pidFile);
        }
      } catch {
        try {
          unlinkSync(this.paths.pidFile);
        } catch {
        }
      }
    }
    return true;
  }
  writePidFile() {
    writeFileSync(this.paths.pidFile, process.pid.toString());
    this.log("INFO", "daemon", "PID file created", {
      pid: process.pid,
      file: this.paths.pidFile
    });
  }
  updateStatus() {
    const status = {
      running: true,
      pid: process.pid,
      startTime: this.startTime,
      uptime: Date.now() - this.startTime,
      services: {
        context: {
          enabled: this.config.context.enabled,
          lastRun: this.contextService.getState().lastSaveTime || void 0,
          saveCount: this.contextService.getState().saveCount
        },
        linear: {
          enabled: this.config.linear.enabled,
          lastRun: this.linearService.getState().lastSyncTime || void 0,
          syncCount: this.linearService.getState().syncCount
        },
        fileWatch: {
          enabled: this.config.fileWatch.enabled
        }
      },
      errors: [
        ...this.contextService.getState().errors.slice(-5),
        ...this.linearService.getState().errors.slice(-5)
      ]
    };
    writeDaemonStatus(status);
  }
  setupSignalHandlers() {
    const handleSignal = (signal) => {
      this.log("INFO", "daemon", `Received ${signal}, shutting down`);
      this.shutdown(signal.toLowerCase());
    };
    process.on("SIGTERM", () => handleSignal("SIGTERM"));
    process.on("SIGINT", () => handleSignal("SIGINT"));
    process.on("SIGHUP", () => handleSignal("SIGHUP"));
    process.on("uncaughtException", (err) => {
      this.log("ERROR", "daemon", "Uncaught exception", {
        error: err.message,
        stack: err.stack
      });
      this.shutdown("uncaught_exception");
    });
    process.on("unhandledRejection", (reason) => {
      this.log("ERROR", "daemon", "Unhandled rejection", {
        reason: String(reason)
      });
    });
  }
  cleanup() {
    try {
      if (existsSync(this.paths.pidFile)) {
        unlinkSync(this.paths.pidFile);
        this.log("INFO", "daemon", "PID file removed");
      }
    } catch (e) {
      this.log("WARN", "daemon", "Failed to remove PID file", {
        error: String(e)
      });
    }
    const finalStatus = {
      running: false,
      startTime: this.startTime,
      uptime: Date.now() - this.startTime,
      services: {
        context: {
          enabled: false,
          saveCount: this.contextService.getState().saveCount
        },
        linear: {
          enabled: false,
          syncCount: this.linearService.getState().syncCount
        },
        fileWatch: { enabled: false }
      },
      errors: []
    };
    writeDaemonStatus(finalStatus);
  }
  shutdown(reason) {
    if (this.isShuttingDown) return;
    this.isShuttingDown = true;
    this.log("INFO", "daemon", "Daemon shutting down", {
      reason,
      uptime: Date.now() - this.startTime,
      contextSaves: this.contextService.getState().saveCount,
      linearSyncs: this.linearService.getState().syncCount
    });
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
      this.heartbeatInterval = void 0;
    }
    this.contextService.stop();
    this.linearService.stop();
    this.cleanup();
    const exitCode = reason === "sigterm" || reason === "sigint" || reason === "sighup" ? 0 : 1;
    process.exit(exitCode);
  }
  async start() {
    if (!this.checkIdempotency()) {
      this.log("INFO", "daemon", "Exiting - daemon already running");
      process.exit(0);
    }
    this.startTime = Date.now();
    this.writePidFile();
    this.setupSignalHandlers();
    this.log("INFO", "daemon", "Unified daemon started", {
      pid: process.pid,
      config: {
        context: this.config.context.enabled,
        linear: this.config.linear.enabled,
        fileWatch: this.config.fileWatch.enabled
      }
    });
    this.contextService.start();
    await this.linearService.start();
    this.heartbeatInterval = setInterval(() => {
      this.updateStatus();
    }, this.config.heartbeatInterval * 1e3);
    this.updateStatus();
  }
  getStatus() {
    return {
      running: !this.isShuttingDown,
      pid: process.pid,
      startTime: this.startTime,
      uptime: Date.now() - this.startTime,
      services: {
        context: {
          enabled: this.config.context.enabled,
          lastRun: this.contextService.getState().lastSaveTime || void 0,
          saveCount: this.contextService.getState().saveCount
        },
        linear: {
          enabled: this.config.linear.enabled,
          lastRun: this.linearService.getState().lastSyncTime || void 0,
          syncCount: this.linearService.getState().syncCount
        },
        fileWatch: {
          enabled: this.config.fileWatch.enabled
        }
      },
      errors: [
        ...this.contextService.getState().errors,
        ...this.linearService.getState().errors
      ]
    };
  }
}
if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("unified-daemon.js")) {
  const args = process.argv.slice(2);
  const config = {};
  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    if (arg === "--save-interval" && args[i + 1]) {
      config.context = { enabled: true, interval: parseInt(args[i + 1], 10) };
      i++;
    } else if (arg === "--linear-interval" && args[i + 1]) {
      config.linear = {
        enabled: true,
        interval: parseInt(args[i + 1], 10),
        retryAttempts: 3,
        retryDelay: 3e4
      };
      i++;
    } else if (arg === "--no-linear") {
      config.linear = {
        enabled: false,
        interval: 60,
        retryAttempts: 3,
        retryDelay: 3e4
      };
    } else if (arg === "--log-level" && args[i + 1]) {
      config.logLevel = args[i + 1];
      i++;
    }
  }
  const daemon = new UnifiedDaemon(config);
  daemon.start().catch((err) => {
    console.error("Failed to start daemon:", err);
    process.exit(1);
  });
}
export {
  UnifiedDaemon
};
//# sourceMappingURL=unified-daemon.js.map
