/**
 * PULSE API sidecar manager.
 *
 * Auto-starts the PULSE API server as a child process if it's not already running.
 * Uses `python -m pulse.api.pulse_api` for cross-platform compatibility.
 */

import { execFile, spawn, type ChildProcess } from "node:child_process";
import { promisify } from "node:util";

const execFileAsync = promisify(execFile);

interface Logger {
  info(msg: string): void;
  warn(msg: string): void;
  error(msg: string): void;
}

export class PulseSidecar {
  private process: ChildProcess | null = null;
  private logger: Logger;

  constructor(logger: Logger) {
    this.logger = logger;
  }

  /** Check if the `pulse` Python package is importable. */
  async checkInstalled(): Promise<boolean> {
    try {
      await execFileAsync("python", ["-c", "import pulse"], {
        timeout: 5_000,
      });
      return true;
    } catch {
      // Try python3 fallback (Linux/macOS)
      try {
        await execFileAsync("python3", ["-c", "import pulse"], {
          timeout: 5_000,
        });
        return true;
      } catch {
        return false;
      }
    }
  }

  /** Detect which python command is available. */
  private async getPythonCmd(): Promise<string> {
    try {
      await execFileAsync("python", ["--version"], { timeout: 3_000 });
      return "python";
    } catch {
      return "python3";
    }
  }

  /** Start the PULSE API server as a background child process. */
  async start(): Promise<void> {
    if (this.process) {
      this.logger.info("[PULSE] Sidecar already running.");
      return;
    }

    const installed = await this.checkInstalled();
    if (!installed) {
      this.logger.error(
        "[PULSE] Python package not found. Install with: pip install pulse-os"
      );
      return;
    }

    const pythonCmd = await this.getPythonCmd();
    this.logger.info(`[PULSE] Starting API sidecar via ${pythonCmd}...`);

    this.process = spawn(pythonCmd, ["-m", "pulse.api.pulse_api"], {
      stdio: "ignore",
      detached: true,
    });

    this.process.unref();

    this.process.on("error", (err) => {
      this.logger.error(`[PULSE] Sidecar error: ${err.message}`);
      this.process = null;
    });

    this.process.on("exit", (code) => {
      if (code !== 0 && code !== null) {
        this.logger.warn(`[PULSE] Sidecar exited with code ${code}`);
      }
      this.process = null;
    });
  }

  /** Stop the sidecar process if running. */
  stop(): void {
    if (this.process) {
      this.process.kill("SIGTERM");
      this.process = null;
      this.logger.info("[PULSE] Sidecar stopped.");
    }
  }

  get isRunning(): boolean {
    return this.process !== null;
  }
}
