import cp from "child_process";
import fs from "fs";
import path from "path";

const internalDeploy = process.env.INTERNAL_DEPLOY === "true";
const executorUrl = process.env.EXECUTOR_URL;
const executorScriptOnly = process.env.EXECUTOR_SCRIPT_ONLY === "true";
const executorBin = process.env.EXECUTOR_BIN ?? `qltr-executor${executorScriptOnly ? ".js": ""}`;

const qualiteerUrl = process.env.QUALITEER_URL ?? "file:///home/runner/Qualiteer/bin/executor";

const kubCmd = "kubectl apply -f";
const jobsDir = "jobs/";
const defaults = JSON.parse(
  fs.readFileSync(path.resolve("./lib/core/k8s-job.json"))
);

const wrapCommand = (jobId, command) => {
  const bin = executorScriptOnly ? `node ${executorBin}`:`chmod +x ${executorBin} && ./${executorBin}`;
  const cmd = command.map((arg)=>JSON.stringify(arg))
  const curlCmd = `curl -o qltr-executor ${executorUrl} && ${bin} ${qualiteerUrl} ${jobId} ${cmd.join(" ")}`;
  return curlCmd;
}

const createFile = (job) => {
  const { name } = job.metadata;
  const jobsPath = path.resolve(jobsDir);
  if (!fs.existsSync(jobsPath)) fs.mkdirSync(jobsPath);
  const filePath = path.resolve(jobsDir, `${name}.json`);
  fs.writeFileSync(filePath, JSON.stringify(job));
  return filePath;
};

const applyFileInternally = (filePath) => {
  const job = fs.readFileSync(filePath, { encoding: "utf8" });
  cp.fork(path.resolve("./lib/core/internal-deploy.js"), [job]);
};

const applyFile = async (filePath) => {
  const command = `${kubCmd} ${filePath}`;
  return new Promise((res, rej) =>
    cp.exec(command, (err, stdout, stderr) => (err && rej(err)) || res(stdout))
  );
};

const deleteFile = (filePath) => fs.unlinkSync(filePath);

const jobBuilder = (jobRequest) => {
  const { resources, name, image, command, id: jobId } = jobRequest;

  // Safety Checks
  if (!jobId) throw Error("'jobId' required!");
  if (!name) throw Error("'name' required!");
  if (!command) throw Error("'command' required!");
  if (!image) throw Error("'image' required!");

  if (!Array.isArray(command)) throw Error("'command' must be an array!");

  // Apply configuration
  const job = { ...defaults };
  job.metadata.name = `qltr-${name}-${jobId}`;
  const container = job.spec.template.spec.containers[0];
  container.name = job.metadata.name;
  container.command = wrapCommand(jobId, command);
  container.image = JSON.stringify(image);

  // Apply resources
  job.resources = { ...job.resources, ...resources };
  return job;
};

export default async function createJob(jobRequest) {
  const job = jobBuilder(jobRequest);
  const filePath = createFile(job);
  if (!internalDeploy) await applyFile(filePath);
  else await applyFileInternally(filePath);
  deleteFile(filePath);
}
