#!/usr/bin/env bash

# bootstrap with nothing configured succeeds and does nothing
cat <<EOF >mise.toml
[tools]
EOF
assert_succeed "mise bootstrap --yes"

# bootstrap applies dotfiles, installs tools, and runs the
# `bootstrap` task afterwards, with the installed tools on PATH
echo "gitconfig content" >gitconfig
cat <<'EOF' >mise.toml
[tools]
tiny = "1.0.0"

[dotfiles]
"~/.gitconfig" = "gitconfig"
"~/.zshrc/activate" = { block = 'eval "$(mise activate zsh)"' }

# the task only succeeds if the installed tool is on PATH
[tasks.bootstrap]
run = "command -v rtx-tiny && echo task-done > bootstrap_ran"
EOF
assert_succeed "mise bootstrap --yes"
assert "cat bootstrap_ran" "task-done"
assert_contains "mise ls tiny" "1.0.0"
assert "readlink ~/.gitconfig" "$PWD/gitconfig"
assert_contains "cat ~/.zshrc" ">>> mise:activate >>>"

# idempotent: re-running is fine
assert_succeed "mise bootstrap --yes"

# dry-run doesn't install or run anything
rm -f bootstrap_ran
cat <<EOF >mise.toml
[tools]
tiny = "2.1.0"

[tasks.bootstrap]
run = "touch bootstrap_ran"
EOF
assert_succeed "mise bootstrap --dry-run"
assert_directory_not_exists "$MISE_DATA_DIR/installs/tiny/2.1.0"
assert_fail "cat bootstrap_ran"

# --skip tools leaves configured tools uninstalled
cat <<EOF >mise.toml
[tools]
tiny = "2.2.0"

[tasks.bootstrap]
run = "touch bootstrap_ran"
EOF
rm -f bootstrap_ran
assert_succeed "mise bootstrap --yes --skip tools"
assert_directory_not_exists "$MISE_DATA_DIR/installs/tiny/2.2.0"
assert "test -f bootstrap_ran"

# comma-separated skips are supported
rm -f bootstrap_ran
cat <<EOF >mise.toml
[tools]
tiny = "2.3.0"

[tasks.bootstrap]
run = "touch bootstrap_ran"
EOF
assert_succeed "mise bootstrap --yes --skip tools,task"
assert_directory_not_exists "$MISE_DATA_DIR/installs/tiny/2.3.0"
assert_fail "test -f bootstrap_ran"

# repeated --skip flags are supported
echo "skipped gitconfig content" >gitconfig-skipped
rm -f bootstrap_ran
cat <<EOF >mise.toml
[dotfiles]
"~/.bootstrap-skip-gitconfig" = "gitconfig-skipped"

[tasks.bootstrap]
run = "touch bootstrap_ran"
EOF
assert_succeed "mise bootstrap --yes --skip dotfiles --skip task"
assert_fail "test -e ~/.bootstrap-skip-gitconfig"
assert_fail "test -f bootstrap_ran"

# --skip dotfiles still reloads config written by earlier phases
rm -f mise.local.toml config_task_ran
cat <<'EOF' >mise.toml
[bootstrap.hooks.post-packages]
run = 'printf "[tasks.bootstrap]\nrun = \"touch config_task_ran\"\n" > mise.local.toml'
EOF
assert_succeed "mise bootstrap --yes --skip dotfiles --skip tools"
assert "test -f config_task_ran"
rm -f mise.local.toml config_task_ran

# skipped parts also skip their directly associated hooks
rm -f pre_packages_hook post_packages_hook pre_tools_hook post_tools_hook final_hook
cat <<'EOF' >mise.toml
[bootstrap.hooks.pre-packages]
run = "touch pre_packages_hook"

[bootstrap.hooks.post-packages]
run = "touch post_packages_hook"

[bootstrap.hooks.pre-tools]
run = "touch pre_tools_hook"

[bootstrap.hooks.post-tools]
run = "touch post_tools_hook"

[bootstrap.hooks.final]
run = "touch final_hook"
EOF
assert_succeed "mise bootstrap --yes --skip packages --skip tools --skip final-hook"
assert_fail "test -f pre_packages_hook"
assert_fail "test -f post_packages_hook"
assert_fail "test -f pre_tools_hook"
assert_fail "test -f post_tools_hook"
assert_fail "test -f final_hook"

# macOS LaunchAgents in shared configs are inert when launchd is unavailable
cat <<EOF >mise.toml
[bootstrap.macos.launchd.agents.my-sync]
program = "~/.local/bin/my-sync"
run_at_load = true
EOF
assert_succeed "mise bootstrap --dry-run"
if [[ $(uname) == "Darwin" ]]; then
  assert_contains "mise bootstrap launchd status" "my-sync"
else
  assert_contains "mise bootstrap launchd status" "skipped"
fi

# systemd user services are declarative and safe to inspect in dry-runs
cat <<EOF >mise.toml
[bootstrap.linux.systemd.units.my-sync]
description = "sync files"
exec_start = "~/.local/bin/my-sync --watch"
restart = "on-failure"
EOF
mkdir -p runtime/systemd/private
XDG_RUNTIME_DIR="$PWD/runtime" assert_succeed "mise bootstrap --dry-run"
XDG_RUNTIME_DIR="$PWD/runtime" assert_contains "mise bootstrap systemd status" "my-sync"

# unavailable system package managers are skipped, not errors
cat <<EOF >mise.toml
[bootstrap.packages]
"apt:bc" = "latest"
"dnf:bc" = "latest"
"pacman:bc" = "latest"
EOF
assert_succeed "mise bootstrap --dry-run"

# dotfiles can add config that contributes hooks to later phases in the same run
mkdir -p dotfiles/mise
cat <<'EOF' >dotfiles/mise/config.toml
[bootstrap.hooks.post-dotfiles]
run = "echo post-dotfiles > post_dotfiles_hook_ran"

[bootstrap.hooks.final]
run = "echo final > final_hook_ran"
EOF
cat <<EOF >mise.toml
[dotfiles]
"~/.config/mise/config.toml" = "dotfiles/mise/config.toml"
EOF
rm -f post_dotfiles_hook_ran final_hook_ran
assert_contains "mise bootstrap --dry-run" "echo post-dotfiles > post_dotfiles_hook_ran"
assert_contains "mise bootstrap --dry-run" "echo final > final_hook_ran"
assert_fail "cat post_dotfiles_hook_ran"
assert_fail "cat final_hook_ran"
assert_succeed "mise bootstrap --yes"
assert "cat post_dotfiles_hook_ran" "post-dotfiles"
assert "cat final_hook_ran" "final"

# bootstrap refuses dotfile conflicts unless scoped force is requested
echo "bootstrap source" >dotfiles/bootstrap-force
cat <<EOF >mise.toml
[dotfiles]
"~/.bootstrap-force-dotfiles" = "dotfiles/bootstrap-force"
EOF
echo "local content" >~/.bootstrap-force-dotfiles
assert_fail "mise bootstrap --yes" "use --force-dotfiles"
assert "cat ~/.bootstrap-force-dotfiles" "local content"
assert_succeed "mise bootstrap --yes --force-dotfiles"
assert "readlink ~/.bootstrap-force-dotfiles" "$PWD/dotfiles/bootstrap-force"

# dry-run previews hooks from templated config dotfiles
cat <<'EOF' >dotfiles/mise/config.local.toml.tmpl
[bootstrap.hooks.final]
run = "echo {{ vars.templated_hook_value }} > templated_hook_ran"
EOF
cat <<EOF >mise.toml
[vars]
templated_hook_value = "template-final"

[dotfiles]
"~/.config/mise/config.local.toml" = { source = "dotfiles/mise/config.local.toml.tmpl", mode = "template" }
EOF
rm -f templated_hook_ran
assert_contains "mise bootstrap --dry-run" "echo template-final > templated_hook_ran"
assert_fail "cat templated_hook_ran"

# dry-run recognizes local config targets such as ~/.mise/config.toml
cat <<'EOF' >dotfiles/mise/local-config.toml
[bootstrap.hooks.post-dotfiles]
run = "echo mise-dir > mise_dir_hook_ran"
EOF
cat <<EOF >mise.toml
[dotfiles]
"~/.mise/config.toml" = "dotfiles/mise/local-config.toml"
EOF
rm -f mise_dir_hook_ran
assert_contains "mise bootstrap --dry-run" "echo mise-dir > mise_dir_hook_ran"
assert_fail "cat mise_dir_hook_ran"
