#!/bin/sh
set -eu

BASE_URL="${BOSUNLY_INSTALL_BASE_URL:-https://bosunly.com}"
MANIFEST_URL="${BASE_URL%/}/cli/manifest.json"
INSTALL_ROOT="${BOSUNLY_INSTALL_ROOT:-${HOME}/.local/share/bosunly/standalone/current}"
BIN_DIR="${BOSUNLY_INSTALL_BIN_DIR:-${HOME}/.local/bin}"
CONFIG_ROOT="${XDG_CONFIG_HOME:-${HOME}/.config}/bosunly"
OS_NAME="${BOSUNLY_INSTALL_OS:-$(uname -s | tr '[:upper:]' '[:lower:]')}"
ARCH_NAME="${BOSUNLY_INSTALL_ARCH:-$(uname -m)}"
NODE_BIN="${BOSUNLY_NODE_BIN:-node}"

fail() {
  echo "$1" >&2
  exit 1
}

resolve_node_bin() {
  if [ -n "${NODE_BIN:-}" ] && [ -x "$NODE_BIN" ]; then
    printf '%s\n' "$NODE_BIN"
    return 0
  fi

  if command -v "$NODE_BIN" >/dev/null 2>&1; then
    command -v "$NODE_BIN"
    return 0
  fi

  return 1
}

case "$OS_NAME" in
  mingw*|msys*|cygwin*|windows_nt|win32)
    fail "Bosunly supports Windows only through WSL for P1.9. Open a WSL shell and rerun 'curl -fsSL https://bosunly.com/install | sh'."
    ;;
  linux|darwin) ;;
  *)
    fail "Bosunly install is not available on this machine: unsupported operating system '$OS_NAME'."
    ;;
esac

case "$ARCH_NAME" in
  x86_64|amd64) NORMALIZED_ARCH="amd64" ;;
  arm64|aarch64) NORMALIZED_ARCH="arm64" ;;
  *)
    fail "Bosunly install is not available on this machine: unsupported architecture '$ARCH_NAME'."
    ;;
esac

command -v curl >/dev/null 2>&1 || fail "Bosunly install requires curl on PATH."
RESOLVED_NODE_BIN="$(resolve_node_bin)" || fail "Bosunly install requires Node.js on PATH for the standalone Bosunly runtime."

TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/bosunly-install.XXXXXX")"
cleanup() {
  rm -rf "$TMP_DIR"
}
trap cleanup EXIT INT TERM HUP

curl -fsSL "$MANIFEST_URL" -o "$TMP_DIR/manifest.json" || fail "Bosunly install could not reach the installer manifest at $MANIFEST_URL."

VERSION="$(
  "$RESOLVED_NODE_BIN" -e 'const fs = require("node:fs"); const payload = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); const value = String(payload.version || "").trim(); if (!value) { process.exit(1); } process.stdout.write(value);' \
    "$TMP_DIR/manifest.json"
)" || fail "Bosunly install could not validate the installer manifest version."

BUNDLE_URL="$(
  "$RESOLVED_NODE_BIN" -e 'const fs = require("node:fs"); const payload = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); const value = String(payload.bundleUrl || "").trim(); if (!value) { process.exit(1); } process.stdout.write(value);' \
    "$TMP_DIR/manifest.json"
)" || fail "Bosunly install could not validate the installer manifest bundle URL."

curl -fsSL "$BUNDLE_URL" -o "$TMP_DIR/bundle.json" || fail "Bosunly install could not reach the release source at $BUNDLE_URL."

"$RESOLVED_NODE_BIN" - "$TMP_DIR/bundle.json" "$INSTALL_ROOT" "$BIN_DIR" "$CONFIG_ROOT" "$MANIFEST_URL" "$VERSION" "$NORMALIZED_ARCH" "$OS_NAME" <<'EOF'
const fs = require("node:fs");
const path = require("node:path");

function exists(targetPath) {
  try {
    fs.accessSync(targetPath);
    return true;
  } catch {
    return false;
  }
}

function removeIfPresent(targetPath) {
  fs.rmSync(targetPath, {
    force: true,
    recursive: true,
  });
}

const [
  bundlePath,
  installRoot,
  binDir,
  configRoot,
  manifestUrl,
  version,
  normalizedArch,
  osName,
] = process.argv.slice(2);

try {
  const payload = JSON.parse(fs.readFileSync(bundlePath, "utf8"));
  const bundleVersion = String(payload.version || "").trim();
  const bundleKind = String(payload.kind || "").trim();
  const entrypointSource = String(payload.entrypointSource || "");

  if (!bundleVersion || bundleVersion !== version) {
    throw new Error("Bosunly install could not validate the downloaded bundle version.");
  }

  if (bundleKind !== "standalone-node") {
    throw new Error("Bosunly install could not validate the downloaded bundle kind.");
  }

  if (!entrypointSource.trim()) {
    throw new Error("Bosunly install could not validate the downloaded launcher payload.");
  }

  const installStageRoot = `${installRoot}.stage-${process.pid}`;
  const installBackupRoot = `${installRoot}.previous`;
  const launcherPath = path.join(binDir, "bosunly");
  const launcherStagePath = path.join(binDir, `.bosunly.stage-${process.pid}`);
  const launcherBackupPath = `${launcherPath}.previous`;
  const installStatePath = path.join(configRoot, "install.json");
  const installStateStagePath = path.join(
    configRoot,
    `.install.stage-${process.pid}.json`,
  );
  const installStateBackupPath = `${installStatePath}.previous`;
  const releaseMetadata = {
    architecture: normalizedArch,
    currentVersion: version,
    executablePath: launcherPath,
    installMethod: "standalone-node",
    installRoot,
    manifestUrl,
    operatingSystem: osName,
    releaseChannel: "stable",
    version: 1,
  };

  removeIfPresent(installStageRoot);
  removeIfPresent(installBackupRoot);
  removeIfPresent(launcherStagePath);
  removeIfPresent(launcherBackupPath);
  removeIfPresent(installStateStagePath);
  removeIfPresent(installStateBackupPath);

  fs.mkdirSync(path.dirname(installRoot), { recursive: true });
  fs.mkdirSync(binDir, { recursive: true });
  fs.mkdirSync(configRoot, { recursive: true });
  fs.mkdirSync(path.join(installStageRoot, "bin"), { recursive: true });

  fs.writeFileSync(
    path.join(installStageRoot, "release.json"),
    JSON.stringify(payload, null, 2),
    "utf8",
  );
  fs.writeFileSync(
    path.join(installStageRoot, "bin", "bosunly.js"),
    entrypointSource.endsWith("\n") ? entrypointSource : `${entrypointSource}\n`,
    { mode: 0o755 },
  );
  fs.writeFileSync(
    path.join(installStageRoot, "package.json"),
    JSON.stringify(
      {
        name: "@bosunly/cli",
        version,
        bin: {
          bosunly: "./bin/bosunly.js",
        },
      },
      null,
      2,
    ) + "\n",
    "utf8",
  );

  const launcherScript = `#!/bin/sh
set -eu
INSTALL_ROOT=${JSON.stringify(installRoot)}
if [ ! -f "$INSTALL_ROOT/bin/bosunly.js" ] || [ ! -f "$INSTALL_ROOT/package.json" ]; then
  echo "Bosunly standalone install is incomplete or corrupted because the installed CLI runtime is missing." >&2
  exit 1
fi
exec node "$INSTALL_ROOT/bin/bosunly.js" "$@"
`;

  fs.writeFileSync(launcherStagePath, launcherScript, { mode: 0o755 });
  fs.writeFileSync(
    installStateStagePath,
    JSON.stringify(releaseMetadata, null, 2),
    { mode: 0o600 },
  );

  let installBackedUp = false;
  let launcherBackedUp = false;
  let installStateBackedUp = false;

  try {
    if (exists(installRoot)) {
      fs.renameSync(installRoot, installBackupRoot);
      installBackedUp = true;
    }

    fs.renameSync(installStageRoot, installRoot);

    if (exists(launcherPath)) {
      fs.renameSync(launcherPath, launcherBackupPath);
      launcherBackedUp = true;
    }

    fs.renameSync(launcherStagePath, launcherPath);

    if (exists(installStatePath)) {
      fs.renameSync(installStatePath, installStateBackupPath);
      installStateBackedUp = true;
    }

    fs.renameSync(installStateStagePath, installStatePath);
  } catch (error) {
    removeIfPresent(launcherPath);
    if (launcherBackedUp && exists(launcherBackupPath)) {
      fs.renameSync(launcherBackupPath, launcherPath);
    }

    removeIfPresent(installStatePath);
    if (installStateBackedUp && exists(installStateBackupPath)) {
      fs.renameSync(installStateBackupPath, installStatePath);
    }

    removeIfPresent(installRoot);
    if (installBackedUp && exists(installBackupRoot)) {
      fs.renameSync(installBackupRoot, installRoot);
    }

    removeIfPresent(installStageRoot);
    removeIfPresent(launcherStagePath);
    removeIfPresent(installStateStagePath);

    throw error;
  }

  removeIfPresent(installBackupRoot);
  removeIfPresent(launcherBackupPath);
  removeIfPresent(installStateBackupPath);
} catch (error) {
  const message =
    error instanceof Error && error.message
      ? error.message
      : "Bosunly install could not finalize the standalone install.";
  console.error(message);
  process.exit(1);
}
EOF

echo "Bosunly installed successfully. Run 'bosunly --version' to verify version ${VERSION}."
