#!/usr/bin/env bash

source_repo="$PWD/bootstrap-source"
checkout="$PWD/bootstrap-checkout"
dry_checkout="$PWD/bootstrap-dry-checkout"
global_source_repo="$PWD/bootstrap-global-source"
relative_global_source_repo="$PWD/bootstrap-relative-global-source"
bare_global_checkout="$PWD/bootstrap-bare-global-checkout"

# Only the canonical spelling is discoverable in help and completions.
for command in "bootstrap" "bootstrap remote"; do
  assert_contains "mise $command --help" "--adopt"
  assert_not_contains "mise $command --help" "--from-git"
  assert_contains "mise __complete_word__ --shell fish --line 'mise $command --'" "--adopt"
  assert_not_contains "mise __complete_word__ --shell fish --line 'mise $command --'" "--from-git"
done
assert_fail "mise bootstrap --adopt new.git --from-git old.git --dry-run"
assert_fail "mise bootstrap remote --host devbox --adopt new.git --from-git old.git --dry-run"

mkdir -p "$source_repo"
git -C "$source_repo" init -q -b main
git -C "$source_repo" config user.email test@example.com
git -C "$source_repo" config user.name "mise test"

cat <<'EOF' >"$source_repo/mise.work.toml"
[dotfiles]
"~/.bootstrap-from-profile" = "profile"

[tasks.bootstrap]
run = 'printf work-v1 > "$HOME/bootstrap-from-task"'

[bootstrap.hooks.final]
run = 'touch "$HOME/bootstrap-from-hook"'
EOF
echo work-v1 >"$source_repo/profile"
git -C "$source_repo" add .
git -C "$source_repo" commit -qm initial

mkdir -p "$global_source_repo"
git -C "$global_source_repo" init -q -b main
git -C "$global_source_repo" config user.email test@example.com
git -C "$global_source_repo" config user.name "mise test"
cat <<'EOF' >"$global_source_repo/config.work.toml"
[dotfiles]
"~/.bootstrap-from-global" = "global-profile"

[tasks.bootstrap]
run = 'printf global > "$HOME/bootstrap-from-global-task"'
EOF
echo global >"$global_source_repo/global-profile"
git -C "$global_source_repo" add .
git -C "$global_source_repo" commit -qm initial

# --adopt checks out a global config repository directly into the mise
# config directory, so its config participates in the first bootstrap and
# remains the global config for later invocations.
assert_succeed "mise -E work bootstrap --adopt '$global_source_repo' --yes --only dotfiles,task"
assert "git -C '$MISE_CONFIG_DIR' remote get-url origin" "$global_source_repo"
assert "cat ~/.bootstrap-from-global" "global"
assert "cat ~/bootstrap-from-global-task" "global"
assert_contains "mise -E work config ls" "~/.config/mise/config.work.toml"

# The hidden spelling keeps working during the one-month migration window.
assert_contains "mise -E work bootstrap --from-git='$global_source_repo' --yes --only dotfiles 2>&1" 'This will be removed in mise 2026.10.0.'
assert_not_contains "mise -E work bootstrap --adopt='$global_source_repo' --yes --only dotfiles 2>&1" 'deprecated'

mkdir -p "$relative_global_source_repo"
git -C "$relative_global_source_repo" init -q -b main
git -C "$relative_global_source_repo" config user.email test@example.com
git -C "$relative_global_source_repo" config user.name "mise test"
cat <<'EOF' >"$relative_global_source_repo/config.toml"
[tasks.bootstrap]
run = 'printf relative-global > "$HOME/bootstrap-from-relative-global-task"'
EOF
git -C "$relative_global_source_repo" add .
git -C "$relative_global_source_repo" commit -qm initial

# A relative MISE_GLOBAL_CONFIG_FILE is resolved before the child changes into
# the checkout and remains the selected global config during re-execution.
rm -f "$HOME/bootstrap-from-relative-global-task"
assert_succeed "MISE_GLOBAL_CONFIG_FILE=relative-global/config.toml mise bootstrap --adopt '$relative_global_source_repo' --yes --only task"
assert "cat ~/bootstrap-from-relative-global-task" "relative-global"

# A relative MISE_CONFIG_DIR is resolved before the child changes into the
# checkout and remains the config directory during re-execution.
relative_config_checkout="bootstrap-relative-config-checkout"
rm -f "$HOME/bootstrap-from-relative-global-task"
assert_succeed "MISE_CONFIG_DIR='$relative_config_checkout' mise bootstrap --adopt '$relative_global_source_repo' --yes --only task"
assert "git -C '$relative_config_checkout' remote get-url origin" "$relative_global_source_repo"
assert "cat ~/bootstrap-from-relative-global-task" "relative-global"

# A bare relative MISE_GLOBAL_CONFIG_FILE checks out into the current directory
# rather than silently falling back to the default global config directory.
mkdir "$bare_global_checkout"
rm -f "$HOME/bootstrap-from-relative-global-task"
assert_succeed "cd '$bare_global_checkout' && MISE_GLOBAL_CONFIG_FILE=config.toml mise bootstrap --adopt '$relative_global_source_repo' --yes --only task"
assert "git -C '$bare_global_checkout' remote get-url origin" "$relative_global_source_repo"
assert "cat ~/bootstrap-from-relative-global-task" "relative-global"

# The default checkout does not collide with the installer's bootstrap staging
# directory, which may already contain versioned mise binaries.
mkdir -p "$MISE_DATA_DIR/bootstrap"
echo occupied >"$MISE_DATA_DIR/bootstrap/mise-test"
assert_succeed "GIT_DIR=/nonexistent GIT_WORK_TREE=/nonexistent mise -E work bootstrap --from '$source_repo' --yes --only dotfiles"
assert "git -C '$MISE_DATA_DIR/bootstrap-repo' remote get-url origin" "$source_repo"

# Global controls are preserved when mise re-executes from the checkout.
assert_succeed "mise --no-hooks -E work bootstrap --from '$source_repo' --from-dir '$checkout' --yes --only final-hook"
assert_fail "test -e ~/bootstrap-from-hook"

# A missing checkout is cloned, selected profile config is loaded, and its
# regular declarative resources and bootstrap task run from the checkout.
assert_succeed "mise -E work bootstrap --from '$source_repo' --from-dir '$checkout' --yes --only dotfiles,task"
assert "cat ~/.bootstrap-from-profile" "work-v1"
assert "cat ~/bootstrap-from-task" "work-v1"
assert "git -C '$checkout' remote get-url origin" "$source_repo"
assert_succeed "mise --cd '$checkout' -E work bootstrap dotfiles track ~/.bootstrap-from-profile --yes"

# An existing empty destination and a single-component relative destination
# are both valid clone targets.
empty_checkout="$PWD/bootstrap-empty-checkout"
mkdir "$empty_checkout"
assert_succeed "mise -E work bootstrap --from '$source_repo' --from-dir '$empty_checkout' --yes --only dotfiles"
assert "git -C '$empty_checkout' remote get-url origin" "$source_repo"
relative_checkout="bootstrap-relative-checkout"
assert_succeed "mise -E work bootstrap --from '$source_repo' --from-dir '$relative_checkout' --yes --only dotfiles"
assert "git -C '$relative_checkout' remote get-url origin" "$source_repo"

# A reused checkout without --update changes nothing and records no
# "bootstrap --from" generation of its own; a clone or pull does. Its checkout
# summary distinguishes the parent operation from the child bootstrap.
count_from_runs="mise bootstrap dotfiles history --json | jq '[.[] | select((.description // \"\") | contains(\"checkout of $source_repo\"))] | length'"
before="$(eval "$count_from_runs")"
assert_succeed "mise -E work bootstrap --from '$source_repo' --from-dir '$checkout' --yes --only dotfiles"
assert "$count_from_runs" "$before"

# Existing checkouts are reused, while --update fast-forwards before bootstrap.
echo work-v2 >"$source_repo/profile"
perl -pi -e 's/work-v1/work-v2/' "$source_repo/mise.work.toml"
git -C "$source_repo" add .
git -C "$source_repo" commit -qm update
assert_succeed "mise -E work bootstrap --from '$source_repo' --from-dir '$checkout' --update --yes --only dotfiles,task"
assert "cat ~/.bootstrap-from-profile" "work-v2"
assert "cat ~/bootstrap-from-task" "work-v2"
assert "$count_from_runs" "$((before + 1))"

# --dry-run also leaves an existing checkout untouched when --update is set.
echo work-v3 >"$source_repo/profile"
git -C "$source_repo" add .
git -C "$source_repo" commit -qm dry-update
assert_contains "mise -E work bootstrap --from '$source_repo' --from-dir '$checkout' --update --dry-run --only dotfiles" "Would run: git -C"
assert "cat '$checkout/profile'" "work-v2"

# Origin validation compares the raw configured URL, not an insteadOf-rewritten
# transport URL.
git config --global url.file:///rewritten/.insteadOf "$source_repo"
assert_succeed "mise -E work bootstrap --from '$source_repo' --from-dir '$checkout' --yes --only dotfiles"
git config --global --unset-all url.file:///rewritten/.insteadOf

# Dry-run reports a clone without creating its destination.
assert_contains "mise -E work bootstrap --from '$source_repo' --from-dir '$dry_checkout' --dry-run" "Would run: git clone"
assert_directory_not_exists "$dry_checkout"

# Reusing a directory from a different remote fails rather than bootstrapping
# an unexpected repository.
git -C "$checkout" remote set-url origin unexpected
assert_fail "mise -E work bootstrap --from '$source_repo' --from-dir '$checkout' --yes"
