import { readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

import {
  ciToolsRunnerImage,
  defaultServiceIds,
  defaultV02RuntimeEndpoint,
  primitiveValidationTasks,
  proxyEnv
} from "./core.mjs";

const templatesDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "templates");
const templateCache = new Map();

function readTemplate(name) {
  if (!templateCache.has(name)) {
    templateCache.set(name, readFileSync(path.join(templatesDir, name), "utf8"));
  }
  return templateCache.get(name);
}

function renderTemplate(name, replacements = {}) {
  let rendered = readTemplate(name);
  for (const [token, value] of Object.entries(replacements)) {
    if (!rendered.includes(token)) throw new Error(`template ${name} is missing token ${token}`);
    rendered = rendered.replaceAll(token, String(value));
  }
  const unresolved = [...rendered.matchAll(/__HWLAB_[A-Z0-9_]+__/gu)].map((match) => match[0]);
  if (unresolved.length > 0) {
    throw new Error(`template ${name} has unresolved tokens: ${[...new Set(unresolved)].join(", ")}`);
  }
  return rendered;
}

function shellSingleQuote(value) {
  return `'${String(value).replace(/'/g, `'"'"'`)}'`;
}

function ciTimingShellFunction() {
  return readTemplate("ci-timing-functions.sh");
}

function dependencyProxyProbeScript(phase, targetUrl) {
  if (!/^[a-z0-9-]+$/u.test(phase)) throw new Error(`invalid dependency proxy probe phase: ${phase}`);
  return renderTemplate("dependency-proxy-probe.sh", {
    "__HWLAB_PROXY_PHASE_SHELL__": shellSingleQuote(phase),
    "__HWLAB_PROXY_TARGET_SHELL__": shellSingleQuote(targetUrl),
    "__HWLAB_PROXY_PHASE__": phase
  });
}

function curlDownloadProbeFunction() {
  return readTemplate("curl-download-probe.sh");
}

function gitSshShellFunction() {
  return renderTemplate("git-ssh-functions.sh", {
    "// __HWLAB_GITHUB_PROXY_CONNECT_MJS__": readTemplate("github-proxy-connect.mjs")
  });
}

function prepareSourceScript() {
  return renderTemplate("prepare-source.sh", {
    "# __HWLAB_CI_TIMING_SHELL__\n": ciTimingShellFunction(),
    "# __HWLAB_GIT_SSH_SHELL__\n": gitSshShellFunction(),
    "__HWLAB_CI_TOOLS_IMAGE__": ciToolsRunnerImage,
    "__HWLAB_V02_RUNTIME_ENDPOINT__": JSON.stringify(defaultV02RuntimeEndpoint).slice(1, -1),
    "__HWLAB_VALIDATION_TASK_COUNT__": primitiveValidationTasks.length
  });
}

function sourceValidationScript(commands) {
  return [
    "#!/bin/sh",
    "set -eu",
    "git config --global --add safe.directory /workspace/source/repo",
    "cd /workspace/source/repo",
    "test \"$(git rev-parse HEAD)\" = \"$(params.revision)\"",
    ...commands
  ].join("\n") + "\n";
}

function primitiveValidationTaskNames() {
  return primitiveValidationTasks.map((task) => task.name);
}

function primitiveValidationTask(task) {
  return {
    name: task.name,
    runAfter: ["prepare-source"],
    workspaces: [{ name: "source", workspace: "source" }],
    taskSpec: {
      params: [
        { name: "revision" },
        { name: "lane" },
        { name: "catalog-path" },
        { name: "image-tag-mode" },
        { name: "source-branch" },
        { name: "gitops-branch" }
      ],
      workspaces: [{ name: "source" }],
      steps: [{ name: task.name, image: ciToolsRunnerImage, env: proxyEnv(), script: sourceValidationScript(task.commands) }]
    },
    params: [
      { name: "revision", value: "$(params.revision)" },
      { name: "lane", value: "$(params.lane)" },
      { name: "catalog-path", value: "$(params.catalog-path)" },
      { name: "image-tag-mode", value: "$(params.image-tag-mode)" },
      { name: "source-branch", value: "$(params.source-branch)" },
      { name: "gitops-branch", value: "$(params.gitops-branch)" }
    ]
  };
}

function planArtifactsScript() {
  return renderTemplate("plan-artifacts.sh", {
    "__HWLAB_CI_TOOLS_IMAGE__": ciToolsRunnerImage,
    '["__HWLAB_DEFAULT_SERVICE_IDS__"]': JSON.stringify(defaultServiceIds)
  });
}

function perServicePublishScript() {
  return renderTemplate("per-service-publish.sh", {
    "# __HWLAB_CI_TIMING_SHELL__\n": ciTimingShellFunction(),
    "# __HWLAB_DEPENDENCY_PROXY_PROBE__": dependencyProxyProbeScript(
      "service-image-publish-proxy-preflight",
      "http://deb.debian.org/debian/dists/bookworm/InRelease"
    ),
    "__HWLAB_CI_TOOLS_IMAGE__": ciToolsRunnerImage
  });
}

function collectArtifactsScript() {
  return renderTemplate("collect-artifacts.sh", {
    "__HWLAB_CI_TOOLS_IMAGE__": ciToolsRunnerImage
  });
}

function gitopsPromoteScript() {
  return renderTemplate("gitops-promote.sh", {
    "# __HWLAB_CI_TIMING_SHELL__\n": ciTimingShellFunction(),
    "# __HWLAB_GIT_SSH_SHELL__\n": gitSshShellFunction(),
    "__HWLAB_CI_TOOLS_IMAGE__": ciToolsRunnerImage
  });
}

function controlPlaneReconcileScript() {
  return renderTemplate("control-plane-reconcile.sh", {
    "# __HWLAB_DEPENDENCY_PROXY_PROBE__": dependencyProxyProbeScript(
      "control-plane-proxy-preflight",
      "http://deb.debian.org/debian/dists/bookworm/InRelease"
    ),
    "# __HWLAB_GIT_SSH_SHELL__\n": gitSshShellFunction(),
    "__HWLAB_CI_TOOLS_IMAGE__": ciToolsRunnerImage
  });
}

function pollerScript() {
  return renderTemplate("poller.sh", {
    "# __HWLAB_DEPENDENCY_PROXY_PROBE__": dependencyProxyProbeScript(
      "poller-proxy-preflight",
      "http://deb.debian.org/debian/dists/bookworm/InRelease"
    ),
    "# __HWLAB_GIT_SSH_SHELL__\n": gitSshShellFunction(),
    "__HWLAB_CI_TOOLS_IMAGE__": ciToolsRunnerImage
  });
}

export {
  ciTimingShellFunction,
  collectArtifactsScript,
  controlPlaneReconcileScript,
  curlDownloadProbeFunction,
  dependencyProxyProbeScript,
  gitopsPromoteScript,
  gitSshShellFunction,
  perServicePublishScript,
  planArtifactsScript,
  pollerScript,
  prepareSourceScript,
  primitiveValidationTask,
  primitiveValidationTaskNames,
  renderTemplate,
  shellSingleQuote,
  sourceValidationScript
};
