#!/usr/bin/env bash
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TMP="$(mktemp -d "${TMPDIR:-/tmp}/mosaic-next-install-test-XXXXXX")"
trap 'rm -rf "$TMP"' EXIT

FAKE_BIN="$TMP/bin"
HOME_DIR="$TMP/home"
PREFIX="$TMP/prefix"
MOSAIC_HOME="$TMP/mosaic"
STATE="$TMP/state"
LOG="$TMP/npm.log"
mkdir -p "$FAKE_BIN" "$HOME_DIR" "$STATE"
REAL_NODE="$(command -v node)"
export MOSAIC_TEST_REAL_NODE="$REAL_NODE"

cat > "$FAKE_BIN/node" <<'FAKE_NODE'
#!/usr/bin/env bash
set -euo pipefail
if [[ "$*" == *'process.versions.node.split'* ]]; then
  printf '%s' "${MOSAIC_TEST_NODE_MAJOR:-22}"
  exit 0
fi
if [[ "${1:-}" == "--version" ]]; then
  printf 'v%s.0.0\n' "${MOSAIC_TEST_NODE_MAJOR:-22}"
  exit 0
fi
exec "${MOSAIC_TEST_REAL_NODE:?}" "$@"
FAKE_NODE
chmod +x "$FAKE_BIN/node"

cat > "$FAKE_BIN/npm" <<'FAKE_NPM'
#!/usr/bin/env bash
set -euo pipefail
LOG="${MOSAIC_TEST_NPM_LOG:?}"
STATE="${MOSAIC_TEST_STATE:?}"
echo "$*" >> "$LOG"

if [[ "$1" == "view" ]]; then
  case "$2 $3" in
    "@mosaicstack/mosaic@next version") echo "0.0.49-next.999" ;;
    "@mosaicstack/gateway@next version") echo "${MOSAIC_TEST_GATEWAY_NEXT_VERSION:-0.0.7-next.999}" ;;
    "@mosaicstack/mosaic version") echo "0.0.48" ;;
    *) echo "unexpected npm view: $*" >&2; exit 1 ;;
  esac
  exit 0
fi

if [[ "$1" == "install" ]]; then
  case "$*" in
    *"@mosaicstack/mosaic@0.0.49-next.999"*)
      echo "0.0.49-next.999" > "$STATE/mosaic"
      ;;
    *"@mosaicstack/gateway@0.0.7-next.999"*)
      if [[ "${MOSAIC_TEST_FAIL_NEXT_GATEWAY_INSTALL:-0}" == "1" ]]; then
        echo "forced gateway install failure" >&2
        exit 1
      fi
      echo "0.0.7-next.999" > "$STATE/gateway"
      ;;
    *"mosaicstack-mosaic-0.0.0-source.tgz"*)
      echo "0.0.0-source" > "$STATE/mosaic"
      ;;
    *"mosaicstack-gateway-0.0.0-source.tgz"*)
      echo "0.0.0-source" > "$STATE/gateway"
      ;;
    *) echo "unexpected npm install: $*" >&2; exit 1 ;;
  esac
  exit 0
fi

if [[ "$1" == "ls" ]]; then
  cli="$(cat "$STATE/mosaic" 2>/dev/null || true)"
  gateway="$(cat "$STATE/gateway" 2>/dev/null || true)"
  node -e '
    const cli = process.argv[1];
    const gateway = process.argv[2];
    const dependencies = {};
    if (cli) dependencies["@mosaicstack/mosaic"] = { version: cli };
    if (gateway) dependencies["@mosaicstack/gateway"] = { version: gateway };
    process.stdout.write(JSON.stringify({ dependencies }));
  ' "$cli" "$gateway"
  exit 0
fi

echo "unexpected npm command: $*" >&2
exit 1
FAKE_NPM
chmod +x "$FAKE_BIN/npm"

cat > "$FAKE_BIN/curl" <<'FAKE_CURL'
#!/usr/bin/env bash
set -euo pipefail
# The fake tar creates the source tree; curl only needs to keep the pipe alive.
exit 0
FAKE_CURL
chmod +x "$FAKE_BIN/curl"

cat > "$FAKE_BIN/tar" <<'FAKE_TAR'
#!/usr/bin/env bash
set -euo pipefail
dest=""
while [[ $# -gt 0 ]]; do
  case "$1" in
    -C) dest="$2"; shift 2 ;;
    *) shift ;;
  esac
done
if [[ -z "$dest" ]]; then
  echo "fake tar missing -C destination" >&2
  exit 1
fi
mkdir -p "$dest/stack/packages/mosaic" "$dest/stack/apps/gateway"
FAKE_TAR
chmod +x "$FAKE_BIN/tar"

cat > "$FAKE_BIN/pnpm" <<'FAKE_PNPM'
#!/usr/bin/env bash
set -euo pipefail
LOG="${MOSAIC_TEST_NPM_LOG:?}"
echo "pnpm $*" >> "$LOG"

if [[ "$1" == "pack" ]]; then
  out=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --pack-destination) out="$2"; shift 2 ;;
      *) shift ;;
    esac
  done
  if [[ -z "$out" ]]; then
    echo "fake pnpm pack missing destination" >&2
    exit 1
  fi
  mkdir -p "$out"
  case "$PWD" in
    */apps/gateway) touch "$out/mosaicstack-gateway-0.0.0-source.tgz" ;;
    */packages/mosaic) touch "$out/mosaicstack-mosaic-0.0.0-source.tgz" ;;
    *) echo "unexpected pnpm pack cwd: $PWD" >&2; exit 1 ;;
  esac
  exit 0
fi

# install/build commands are no-ops in this harness.
exit 0
FAKE_PNPM
chmod +x "$FAKE_BIN/pnpm"

reset_state() {
  : > "$LOG"
  rm -f "$STATE"/*
}

reset_state
echo "[test] --next rejects Node 20 before any install action"
if OUTPUT="$(
  HOME="$HOME_DIR" MOSAIC_HOME="$MOSAIC_HOME" MOSAIC_PREFIX="$PREFIX" MOSAIC_NO_COLOR=1 \
  MOSAIC_TEST_NPM_LOG="$LOG" MOSAIC_TEST_STATE="$STATE" MOSAIC_TEST_REAL_NODE="$REAL_NODE" \
  MOSAIC_TEST_NODE_MAJOR=20 PATH="$FAKE_BIN:$PATH" \
  bash "$ROOT/tools/install.sh" --cli --next --yes --no-auto-launch 2>&1
)"; then
  echo "expected Node 20 next-lane install to fail" >&2
  exit 1
fi
grep -qF 'Node.js >= 22 required for the --next lane' <<<"$OUTPUT"
[[ ! -s "$LOG" ]] || { echo "Node 20 gate ran npm actions" >&2; exit 1; }

reset_state
echo "[test] --next fast path pins resolved package versions"
OUTPUT="$(
  HOME="$HOME_DIR" \
  MOSAIC_HOME="$MOSAIC_HOME" \
  MOSAIC_PREFIX="$PREFIX" \
  MOSAIC_NO_COLOR=1 \
  MOSAIC_TEST_NPM_LOG="$LOG" \
  MOSAIC_TEST_STATE="$STATE" \
  PATH="$FAKE_BIN:$PATH" \
  bash "$ROOT/tools/install.sh" --cli --next --yes --no-auto-launch
)"

grep -qF 'Installed @next packages: CLI 0.0.49-next.999, gateway 0.0.7-next.999' <<<"$OUTPUT"
grep -qF 'install -g @mosaicstack/gateway@0.0.7-next.999' "$LOG"
grep -qF 'install -g @mosaicstack/mosaic@0.0.49-next.999' "$LOG"
if grep -qE '^install -g .+@next( |$)' "$LOG"; then
  echo "expected exact-version installs, found mutable @next install" >&2
  exit 1
fi
if grep -qF 'Downloading source from next' <<<"$OUTPUT"; then
  echo "fast path unexpectedly fell back to source" >&2
  exit 1
fi

reset_state
echo "[test] fast path failure falls back to source build"
OUTPUT="$(
  HOME="$HOME_DIR" \
  MOSAIC_HOME="$MOSAIC_HOME" \
  MOSAIC_PREFIX="$PREFIX" \
  MOSAIC_NO_COLOR=1 \
  MOSAIC_TEST_NPM_LOG="$LOG" \
  MOSAIC_TEST_STATE="$STATE" \
  MOSAIC_TEST_FAIL_NEXT_GATEWAY_INSTALL=1 \
  PATH="$FAKE_BIN:$PATH" \
  bash "$ROOT/tools/install.sh" --cli --next --yes --no-auto-launch
)"

grep -qF 'Fast gateway @next install failed.' <<<"$OUTPUT"
grep -qF 'Falling back to source build at ref next; --next will not hard-fail on registry issues.' <<<"$OUTPUT"
grep -qF 'Downloading source from next' <<<"$OUTPUT"
grep -qF 'Installed from source: CLI 0.0.0-source' <<<"$OUTPUT"
grep -qF 'install -g @mosaicstack/mosaic@0.0.49-next.999' "$LOG"
grep -qE 'install -g .*/mosaicstack-gateway-0\.0\.0-source\.tgz' "$LOG"
grep -qE 'install -g .*/mosaicstack-mosaic-0\.0\.0-source\.tgz' "$LOG"
[[ "$(cat "$STATE/mosaic")" == "0.0.0-source" ]]
[[ "$(cat "$STATE/gateway")" == "0.0.0-source" ]]

reset_state
echo "[test] explicit --ref keeps source lane and avoids @next lookup"
OUTPUT="$(
  HOME="$HOME_DIR" \
  MOSAIC_HOME="$MOSAIC_HOME" \
  MOSAIC_PREFIX="$PREFIX" \
  MOSAIC_NO_COLOR=1 \
  MOSAIC_TEST_NPM_LOG="$LOG" \
  MOSAIC_TEST_STATE="$STATE" \
  PATH="$FAKE_BIN:$PATH" \
  bash "$ROOT/tools/install.sh" --check --cli --next --ref feature-x
)"

grep -qF 'explicit ref wins, build-from-source' <<<"$OUTPUT"
if grep -qF '@next version' "$LOG"; then
  echo "explicit ref should not query @next dist-tags" >&2
  exit 1
fi

reset_state
echo "[test] --check --next warns on mismatched prerelease pipeline suffixes"
OUTPUT="$(
  HOME="$HOME_DIR" \
  MOSAIC_HOME="$MOSAIC_HOME" \
  MOSAIC_PREFIX="$PREFIX" \
  MOSAIC_NO_COLOR=1 \
  MOSAIC_TEST_NPM_LOG="$LOG" \
  MOSAIC_TEST_STATE="$STATE" \
  MOSAIC_TEST_GATEWAY_NEXT_VERSION="0.0.7-next.1000" \
  PATH="$FAKE_BIN:$PATH" \
  bash "$ROOT/tools/install.sh" --check --cli --next
)"

grep -qF '@next registry lane incomplete, mismatched, or unreachable; --next would fall back to source.' <<<"$OUTPUT"

echo "[test] installer next lane tests passed"
