#!/usr/bin/env bash

# An explicit fuzzy version must not prevent --bump from updating the config.
cat <<'EOF' >mise.toml
[tools]
dummy = "1.0.0"
EOF
mise install dummy@1.0.0
mise install dummy@2.0.0

output=$(mise up --bump dummy@latest --dry-run)
assert_contains "echo '$output'" "Would bump dummy@latest"
assert_contains "cat mise.toml" 'dummy = "1.0.0"'

mise up --bump dummy@latest --prune
assert_contains "mise ls dummy" "dummy  2.0.0  ~/workdir/mise.toml  latest"
assert_contains "cat mise.toml" 'dummy = "latest"'

# Subsequent bumps retain the latest selector and a concrete lockfile version.
MISE_LOCKFILE=1 mise lock
MISE_LOCKFILE=1 mise up --bump dummy --prune
assert_contains "cat mise.toml" 'dummy = "latest"'
assert_contains "cat mise.lock" 'version = "2.0.0"'

# Pinning saves the resolved version, including when already installed.
output=$(MISE_PIN=1 mise up --bump dummy@latest --dry-run)
assert_contains "echo '$output'" "Would bump dummy@2.0.0"
MISE_PIN=1 mise up --bump dummy@latest --prune
assert_contains "cat mise.toml" 'dummy = "2.0.0"'

# Explicit selectors constrain resolution and are persisted verbatim.
cat <<'EOF' >mise.toml
[tools]
dummy = "1.0.0"
EOF
mise install dummy@3.1.0

output=$(mise up --bump dummy@3 --dry-run)
assert_contains "echo '$output'" "Would bump dummy@3"
assert_contains "cat mise.toml" 'dummy = "1.0.0"'

# An already-installed explicit selector is still persisted when another tool
# needs a regular upgrade.
cat <<'EOF' >mise.toml
[tools]
dummy = "1.0.0"
tiny-local = "1.0.0"
EOF
ln -s "$ROOT/test/data/plugins/tiny" "$MISE_DATA_DIR/plugins/tiny-local"
mise install dummy@3.1.0
mise install tiny-local@1.0.0
mise up --bump dummy@3 tiny-local --prune
assert_contains "cat mise.toml" 'dummy = "3"'
assert_contains "cat mise.toml" 'tiny-local = "3.1.0"'

# An unresolved explicit selector must not prevent a successful sibling bump.
cat <<'EOF' >mise.toml
[tools]
dummy = "1.0.0"
tiny-local = "1.0.0"
EOF
mise install tiny-local@1.0.0

# Dry runs omit failed selectors, including when another selector for the same
# backend succeeds, but retain installed selectors and pending explicit installs.
mise uninstall tiny-local@3.1.0
output=$(mise up --bump dummy@path:/does-not-exist dummy@3 tiny-local@3.1 --dry-run 2>&1)
assert_not_contains_text "$output" "Would bump dummy@path:/does-not-exist"
assert_not_contains_text "$output" "Would bump dummy@1.0.0"
assert_contains_text "$output" "Would bump dummy@3"
assert_contains_text "$output" "Would bump tiny-local@3.1"
assert_contains "cat mise.toml" 'dummy = "1.0.0"'
assert_contains "cat mise.toml" 'tiny-local = "1.0.0"'

mise up --bump dummy@path:/does-not-exist tiny-local --prune >/dev/null 2>&1 || :
assert_contains "cat mise.toml" 'dummy = "1.0.0"'
assert_contains "cat mise.toml" 'tiny-local = "3.1.0"'

mise up --bump dummy@3 --prune
assert_contains "cat mise.toml" 'dummy = "3"'

# An explicit selector must constrain the installed version instead of merely
# changing the selector that gets persisted.
cat <<'EOF' >mise.toml
[tools]
tiny-local = "1.0.0"
EOF
mise install tiny-local@1.0.0
MISE_LOCKFILE=1 mise lock
output=$(MISE_LOCKFILE=1 mise up --bump tiny-local@2 --dry-run 2>&1)
assert_contains_text "$output" "Would install tiny-local@2.1.0"
assert_contains_text "$output" "Would bump tiny-local@2"
assert_contains "cat mise.toml" 'tiny-local = "1.0.0"'
MISE_LOCKFILE=1 mise up --bump tiny-local@2 --prune
assert_contains "cat mise.toml" 'tiny-local = "2"'
assert_contains "mise ls tiny-local" "2.1.0"
assert_contains "cat mise.lock" '2.1.0'

# A config-only explicit bump must also refresh an existing lockfile.
cat <<'EOF' >mise.toml
[tools]
tiny-local = "1.0.0"
EOF
MISE_LOCKFILE=1 mise lock
output=$(MISE_LOCKFILE=1 mise up --bump tiny-local@3 --prune 2>&1)
assert_not_contains_text "$output" "All tools are up to date"
assert_not_contains_text "$output" "Newer versions are available but do not match"
assert_contains "cat mise.toml" 'tiny-local = "3"'
assert_contains "cat mise.lock" '3.1.0'

# Excluded explicit bumps must not update the configuration, whether they are
# the only requested tool or run alongside another upgrade.
cat <<'EOF' >mise.toml
[tools]
dummy = "1.0.0"
EOF
mise install dummy@3.1.0
mise up --bump dummy@3 --exclude dummy --prune
assert_contains "cat mise.toml" 'dummy = "1.0.0"'

cat <<'EOF' >mise.toml
[tools]
dummy = "1.0.0"
tiny-local = "1.0.0"
EOF
mise install dummy@3.1.0
mise install tiny-local@1.0.0
mise up --bump dummy@3 tiny-local --exclude dummy --prune
assert_contains "cat mise.toml" 'dummy = "1.0.0"'
assert_contains "cat mise.toml" 'tiny-local = "3.1.0"'

cat <<'EOF' >mise.toml
[tools]
dummy = "1.0.0"
EOF
mise up --bump dummy@3.1 --prune
assert_contains "cat mise.toml" 'dummy = "3.1"'

# A higher-precedence environment request is not a writable config source.
cat <<'EOF' >mise.toml
[tools]
dummy = "1.0.0"
EOF
MISE_DUMMY_VERSION=1.0.0 mise up --bump dummy@latest --prune
assert_contains "cat mise.toml" 'dummy = "1.0.0"'

# An unresolved explicit selector must not overwrite a working configuration.
cat <<'EOF' >mise.toml
[tools]
dummy = "1.0.0"
EOF
mise up --bump dummy@path:/does-not-exist --prune >/dev/null 2>&1 || :
assert_contains "cat mise.toml" 'dummy = "1.0.0"'

# Concrete selectors and successful typed selectors persist their own request.
cat <<'EOF2' >mise.toml
[tools]
dummy = "1.0.0"
EOF2
mise install dummy@3.1.0
mise up --bump dummy@3.1.0 --prune
assert_contains "cat mise.toml" 'dummy = "3.1.0"'

cat <<'EOF2' >mise.toml
[tools]
dummy = "1.0.0"
EOF2
mise install dummy@3.1.0
mise up --bump dummy@prefix:3 --prune
assert_contains "cat mise.toml" 'dummy = "prefix:3"'

# A failed selector for the same backend must not be retained when its sibling succeeds.
cat <<'EOF2' >mise.toml
[tools]
dummy = "1.0.0"
EOF2
mise up --bump dummy@3 dummy@path:/does-not-exist --prune >/dev/null 2>&1 || :
assert_contains "cat mise.toml" 'dummy = "3"'

# Pinning also applies uniformly to other version selectors.
MISE_PIN=1 mise up --bump dummy@3 --prune
assert_contains "cat mise.toml" 'dummy = "3.1.0"'

# Exercise the install path with a fully qualified backend request.
ln -s "$ROOT/test/data/plugins/tiny" "$MISE_DATA_DIR/plugins/asdf-tiny-local"
cat <<'EOF' >mise.toml
[tools]
tiny-local = "1.0.0"
EOF
mise uninstall tiny-local@3.1.0
mise up --bump asdf:tiny-local@latest --prune
assert_contains "cat mise.toml" 'tiny-local = "latest"'
mise uninstall asdf:tiny-local@3.1.0
MISE_PIN=1 mise up --bump asdf:tiny-local@latest --prune
assert_contains "cat mise.toml" 'tiny-local = "3.1.0"'
mise up --bump asdf:tiny-local@latest --prune
assert_contains "cat mise.toml" 'tiny-local = "latest"'

# Explicit ref, branch, and revision selectors are persisted verbatim.
for selector in ref:master branch:master rev:master; do
  cat <<'EOF2' >mise.toml
[tools]
dummy = "1.0.0"
EOF2
  mise install "dummy@$selector"
  mise up --bump "dummy@$selector" --prune
  assert_contains "cat mise.toml" "dummy = \"$selector\""
done

# A system selector is persisted when the system executable is available.
mkdir -p bin
cat <<'EOF2' >bin/dummy
#!/usr/bin/env bash
exit 0
EOF2
chmod +x bin/dummy
cat <<'EOF2' >mise.toml
[tools]
dummy = "1.0.0"
EOF2
PATH="$PWD/bin:$PATH" mise up --bump dummy@system --prune
assert_contains "cat mise.toml" 'dummy = "system"'

# A failed typed selector must not overwrite a working configuration.
cat <<'EOF2' >mise.toml
[tools]
dummy = "1.0.0"
EOF2
mise up --bump dummy@path:/does-not-exist --prune >/dev/null 2>&1 || :
assert_contains "cat mise.toml" 'dummy = "1.0.0"'
