import { ChildProcess, exec, execSync } from "child_process";
import crypto from "node:crypto";
import { mkdir } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import waitPort from "wait-port";

export type AppType = "--frontend" | "--no-frontend" | "";
const MODEL = "gpt-3.5-turbo";

export async function runApp(
  cwd: string,
  name: string,
  appType: AppType,
  port: number,
): Promise<ChildProcess[]> {
  const cps = [];

  try {
    switch (appType) {
      case "--no-frontend":
        cps.push(
          await createProcess("npm run dev", `${cwd}/${name}/backend`, port),
        );
        break;
      case "--frontend":
        cps.push(
          await createProcess(
            "npm run dev",
            `${cwd}/${name}/backend`,
            port + 1,
          ),
        );
        cps.push(
          await createProcess("npm run dev", `${cwd}/${name}/frontend`, port),
        );
        break;
      default:
        cps.push(await createProcess("npm run dev", `${cwd}/${name}`, port));
        break;
    }
  } catch (e) {
    cps.forEach((cp) => cp.kill());
    throw e;
  }
  return cps;
}

async function createProcess(command: string, cwd: string, port: number) {
  const cp = exec(command, {
    cwd,
    env: {
      ...process.env,
      PORT: `${port}`,
    },
  });
  if (!cp) throw new Error(`Can't start process ${command} in ${cwd}`);

  await waitPort({
    host: "localhost",
    port,
    timeout: 1000 * 60,
  });
  return cp;
}

export function runCreateLlama(
  cwd: string,
  templateType: string,
  templateFramework: string,
  templateEngine: string,
  templateUI: string,
  appType: AppType,
) {
  const createLlama = fileURLToPath(
    new URL("../dist/index.js", import.meta.url),
  );

  const name = [
    templateType,
    templateFramework,
    templateEngine,
    templateUI,
    appType,
  ].join("-");
  const command = [
    "node",
    createLlama,
    name,
    "--template",
    templateType,
    "--framework",
    templateFramework,
    "--engine",
    templateEngine,
    "--ui",
    templateUI,
    "--model",
    MODEL,
    "--open-ai-key",
    "testKey",
    appType,
    "--eslint",
    "--use-npm",
  ].join(" ");
  console.log(`running command '${command}' in ${cwd}`);
  execSync(command, {
    stdio: "inherit",
    cwd,
  });
  return name;
}
export async function createTestDir() {
  const cwd = fileURLToPath(
    new URL(`.cache/${crypto.randomUUID()}`, import.meta.url),
  );
  await mkdir(cwd, { recursive: true });
  return cwd;
}