#!/usr/bin/env node

import crypto from "node:crypto";
import { spawn } from "node:child_process";
import path from "node:path";
import { fileURLToPath } from "node:url";

const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = path.resolve(SCRIPT_DIR, "../../../../../../");

export function findProjectRoot(start = process.cwd()) {
  return path.resolve(start);
}

export function uuidFragment() {
  return crypto.randomBytes(4).toString("hex");
}

export function openInBrowser(target) {
  const platform = process.platform;
  if (platform === "darwin") {
    spawn("open", [target], { detached: true, stdio: "ignore" }).unref();
    return;
  }
  if (platform === "win32") {
    spawn("cmd", ["/c", "start", "", target], { detached: true, stdio: "ignore" }).unref();
    return;
  }
  spawn("xdg-open", [target], { detached: true, stdio: "ignore" }).unref();
}

function getPieCliPath(cwd = process.cwd()) {
  return path.join(REPO_ROOT, "products/cli/dist/cli.js");
}

export async function runPieJsonPrompt(prompt, { cwd = process.cwd(), timeout = 300_000, sessionId = null } = {}) {
  return new Promise((resolve, reject) => {
    const args = [getPieCliPath(cwd), prompt, "--json-output"];
    if (sessionId) {
      args.push("--session-id", sessionId);
    }

    const child = spawn("node", args, {
      cwd,
      env: { ...process.env },
      stdio: ["ignore", "pipe", "pipe"],
    });

    let stdout = "";
    let stderr = "";
    let settled = false;

    const cleanup = () => {
      clearTimeout(timer);
      child.stdout.removeAllListeners();
      child.stderr.removeAllListeners();
      child.removeAllListeners();
    };

    const finish = (cb) => {
      if (settled) return;
      settled = true;
      cleanup();
      try {
        child.kill("SIGKILL");
      } catch {}
      cb();
    };

    const tryResolveFromStdout = () => {
      const lines = stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
      for (let i = lines.length - 1; i >= 0; i -= 1) {
        const line = lines[i];
        if (!line.startsWith("{")) continue;
        try {
          const parsed = JSON.parse(line);
          if (Object.prototype.hasOwnProperty.call(parsed, "ok")) {
            finish(() => resolve(parsed));
            return true;
          }
        } catch {}
      }
      return false;
    };

    const timer = setTimeout(() => {
      finish(() => reject(new Error(`pie prompt timed out after ${Math.round(timeout / 1000)}s`)));
    }, timeout);

    child.stdout.on("data", (chunk) => {
      stdout += String(chunk);
      tryResolveFromStdout();
    });
    child.stderr.on("data", (chunk) => {
      stderr += String(chunk);
    });
    child.on("error", (error) => {
      finish(() => reject(error));
    });
    child.on("close", (code) => {
      if (tryResolveFromStdout()) {
        return;
      }
      finish(() => reject(new Error(`pie prompt exited ${code}\nstdout: ${stdout}\nstderr: ${stderr}`)));
    });
  });
}

export async function callPieText(prompt, { cwd = process.cwd(), timeout = 300_000, sessionId = null } = {}) {
  const response = await runPieJsonPrompt(prompt, { cwd, timeout, sessionId });
  if (!response?.ok) {
    throw new Error(response?.error || "Pie prompt failed");
  }
  return String(response.text || "");
}
