#!/usr/bin/env bash

export MISE_SHIMS_DIR="$HOME/.local/share/mise/user-shims"

# A lazy tool must install the first time a task runs one of its commands, the
# same way it does when the command is typed into an activated shell. Neither a
# shim farm on PATH nor a prior `mise reshim` is required: a hand-edited
# `lazy = true` entry has no shim yet, and a task's shell has no
# command-not-found handler to fall back on (discussion #12678).
case ":$PATH:" in
  *":$MISE_SHIMS_DIR:"*) fail "expected user shims to be absent from PATH: $PATH" ;;
esac
mise use tiny@1.0.0
assert_directory_exists "$MISE_DATA_DIR/installs/tiny/1.0.0"
# Edited by hand: nothing rebuilds the shim farm, so no `dummy` shim exists.
cat >mise.toml <<'EOF'
[tools]
tiny = "1.0.0"
dummy = { version = "1.0.0", lazy = true, lazy_bins = ["dummy"] }

[tasks.check]
run = "dummy --version"
EOF
assert_fail "test -d '$MISE_DATA_DIR/installs/dummy/1.0.0'"
assert_fail "test -e '$MISE_SHIMS_DIR/dummy'"

# With a lazy declaration, the child PATH keeps the shim farm behind tool paths.
mise_path="$(mise env -s bash | sed -n 's/^export PATH=//p' | tr -d "'\"")"
case "$mise_path" in
  "$MISE_DATA_DIR/installs/tiny/1.0.0/bin:$MISE_SHIMS_DIR:"*) ;;
  *) fail "expected tool paths, then the shim farm, then the rest: $mise_path" ;;
esac

assert_contains "MISE_NOT_FOUND_AUTO_INSTALL=0 mise run check" "This is Dummy 1.0.0"
assert_directory_exists "$MISE_DATA_DIR/installs/dummy/1.0.0"
assert_succeed "test -e '$MISE_SHIMS_DIR/dummy'"

# Once installed, the real bin directory precedes the farm.
mise_path="$(mise env -s bash | sed -n 's/^export PATH=//p' | tr -d "'\"")"
case "$mise_path" in
  *"$MISE_DATA_DIR/installs/dummy/1.0.0/bin:"*"$MISE_SHIMS_DIR:"*) ;;
  *) fail "expected the tool bin dir ahead of the shim farm: $mise_path" ;;
esac
assert_contains "mise run check" "This is Dummy 1.0.0"

# A farm already on PATH keeps its place and is not duplicated.
mise_path="$(PATH="$MISE_SHIMS_DIR:$PATH" mise env -s bash | sed -n 's/^export PATH=//p' | tr -d "'\"")"
case "$mise_path" in
  "$MISE_DATA_DIR/installs/tiny/1.0.0/bin:$MISE_DATA_DIR/installs/dummy/1.0.0/bin:$MISE_SHIMS_DIR:"*) ;;
  *) fail "expected tool paths, then the farm from the original PATH: $mise_path" ;;
esac
assert "printf '%s' \"$mise_path\" | tr ':' '\\n' | grep -c -x \"$MISE_SHIMS_DIR\"" "1"

# `mise x -- <cmd>` names the lazy command directly and installs its provider.
cat >mise.toml <<'EOF'
[tools]
tiny = { version = "1.0.0", lazy = true, lazy_bins = ["rtx-tiny"] }
dummy = { version = "1.0.0", lazy = true, lazy_bins = ["dummy"] }
EOF
mise uninstall --all tiny
mise uninstall --all dummy
rm -f "$MISE_SHIMS_DIR/rtx-tiny" "$MISE_SHIMS_DIR/dummy"
output=$(MISE_NOT_FOUND_AUTO_INSTALL=0 mise x -- dummy --version 2>&1)
case "$output" in
  *"missing: dummy@1.0.0"*) fail "lazy provider was reported missing after installation: $output" ;;
esac
case "$output" in
  *"This is Dummy 1.0.0"*) ;;
  *) fail "lazy provider did not run: $output" ;;
esac
assert_directory_exists "$MISE_DATA_DIR/installs/dummy/1.0.0"
assert_fail "test -d '$MISE_DATA_DIR/installs/tiny/1.0.0'"
assert_succeed "test -e '$MISE_SHIMS_DIR/rtx-tiny'"

# A lazy declaration without bin metadata reports its own error without
# preventing bootstrap shims for the remaining valid declarations.
mise uninstall --all dummy
rm -f "$MISE_SHIMS_DIR/dummy"
cat >mise.toml <<'EOF'
[tools]
"aqua:tinygo-org/tinygo" = { version = "0.39.0", lazy = true }
dummy = { version = "1.0.0", lazy = true, lazy_bins = ["dummy"] }

[tasks.valid-lazy]
run = "dummy --version"
EOF
assert_contains "MISE_NOT_FOUND_AUTO_INSTALL=0 mise run valid-lazy 2>&1" "This is Dummy 1.0.0"
assert_directory_exists "$MISE_DATA_DIR/installs/dummy/1.0.0"
assert_succeed "test -e '$MISE_SHIMS_DIR/dummy'"

# Commands started by the child reach the tool through its bootstrap shim.
mise uninstall --all dummy
rm -f "$MISE_SHIMS_DIR/dummy"
assert_contains "MISE_NOT_FOUND_AUTO_INSTALL=0 mise x -- sh -c 'dummy --version'" "This is Dummy 1.0.0"
assert_directory_exists "$MISE_DATA_DIR/installs/dummy/1.0.0"

# Lazy declarations that exist only in a task also get bootstrap shims after
# task tools are collected, not just those in the project toolset.
mise uninstall --all dummy
rm -f "$MISE_SHIMS_DIR/dummy"
ln -s "$(command -v mise)" "$MISE_SHIMS_DIR/unrelated"
cat >mise.toml <<'EOF'
[tasks.task-local]
tools = { dummy = { version = "1.0.0", lazy = true, lazy_bins = ["dummy"] } }
run = 'test -e "$MISE_SHIMS_DIR/unrelated" && dummy --version'
EOF
assert_contains "MISE_NOT_FOUND_AUTO_INSTALL=0 mise run task-local" "This is Dummy 1.0.0"
assert_directory_exists "$MISE_DATA_DIR/installs/dummy/1.0.0"
assert_succeed "test -e '$MISE_SHIMS_DIR/dummy'"

# A nested task without runtime tools must not inherit its parent's serialized
# task toolset. The parent's unused lazy tool remains uninstalled.
mise uninstall --all dummy
cat >mise.toml <<'EOF'
[tasks.parent]
tools = { dummy = { version = "1.0.0", lazy = true, lazy_bins = ["dummy"] } }
run = "mise run no-tools"

[tasks.no-tools]
run = 'test -z "${__MISE_TASK_TOOL_ARGS-}" && echo cleared'
EOF
assert_contains "mise run parent" "cleared"
assert_fail "test -d '$MISE_DATA_DIR/installs/dummy/1.0.0'"

# Without a lazy declaration the child environment leaves the farm off PATH.
cat >mise.toml <<'EOF'
[tools]
dummy = "1.0.0"
EOF
assert_not_contains "mise env -s bash" "$MISE_SHIMS_DIR"
