#!/usr/bin/env bash

# A lazy tool with no version installed is waiting for its first run, not
# outdated. A bare `mise upgrade` leaves it alone, as a bare `mise install` does,
# and naming the tool installs it, as `mise install dummy` does. The dummy
# backend offers 1.0.0, 1.1.0, and 2.0.0.

mise uninstall dummy --all

# Missing and lazy: nothing to upgrade.
cat >"$MISE_CONFIG_DIR/config.toml" <<'EOF'
[tools]
dummy = { version = "latest", lazy = true, lazy_bins = ["dummy"] }
EOF
assert_not_contains "mise upgrade --dry-run 2>&1" "Would install"
assert_succeed "mise upgrade --dry-run-code"
mise upgrade
assert_empty "mise ls --installed dummy"

# The same for a lazy tool declared in system config, such as a distribution's
# defaults, and for `mise upgrade --global`.
rm "$MISE_CONFIG_DIR/config.toml"
cat >"$MISE_SYSTEM_DIR/config.toml" <<'EOF'
[tools]
dummy = { version = "latest", lazy = true, lazy_bins = ["dummy"] }
EOF
mise upgrade
mise upgrade --global
assert_empty "mise ls --installed dummy"

# A range doesn't list it as newer than the range allows, either.
cat >"$MISE_SYSTEM_DIR/config.toml" <<'EOF'
[tools]
dummy = { version = "1", lazy = true, lazy_bins = ["dummy"] }
EOF
upgrade_output=$(mise upgrade 2>&1)
assert_contains_text "$upgrade_output" "All tools are up to date"
assert_not_contains_text "$upgrade_output" "configured version ranges"
assert_empty "mise ls --installed dummy"

# `mise outdated` still lists it, marked so it is clear `mise upgrade` skips it.
assert_contains "mise outdated" "[MISSING] (lazy)"

# `--bump` leaves it alone too.
assert_not_contains "mise upgrade --bump --dry-run 2>&1" "Would install"
assert_empty "mise ls --installed dummy"

# Naming the tool installs it.
assert_contains "mise upgrade dummy --dry-run 2>&1" "Would install dummy@1.1.0"
mise upgrade dummy
assert_contains "mise ls --installed dummy" "1.1.0"

# Once installed, a bare upgrade moves it forward as before.
mise uninstall dummy --all
mise install dummy@1.0.0
mise upgrade --prune
assert_contains "mise ls --installed dummy" "1.1.0"
assert_not_contains "mise ls --installed dummy" "1.0.0"

# Any installed version counts, even one outside the request: the tool has been
# run, so the upgrade installs what the request now selects.
cat >"$MISE_SYSTEM_DIR/config.toml" <<'EOF'
[tools]
dummy = { version = "2", lazy = true, lazy_bins = ["dummy"] }
EOF
mise upgrade
assert_contains "mise ls --installed dummy" "2.0.0"

# A tool the upgrade installs still gets the missing lazy tool it depends on.
mise uninstall dummy --all
cat >"$MISE_SYSTEM_DIR/config.toml" <<'EOF'
[tools]
dummy = { version = "2.0.0", lazy = true, lazy_bins = ["dummy"] }
needs-dummy = { version = "1.0.0", depends = ["dummy"] }
EOF
mise upgrade
assert_contains "mise ls --installed dummy" "2.0.0"
assert_contains "mise ls --installed needs-dummy" "1.0.0"

# A missing tool without lazy still installs.
mise uninstall dummy needs-dummy --all
cat >"$MISE_SYSTEM_DIR/config.toml" <<'EOF'
[tools]
dummy = "latest"
EOF
mise upgrade
assert_contains "mise ls --installed dummy" "2.0.0"

# A tool the upgrade leaves alone is not looked up either, so a backend that
# cannot resolve it neither delays the upgrade nor warns. Naming it does look it up.
cat >"$MISE_SYSTEM_DIR/config.toml" <<'EOF2'
[tools]
"github:mise-test/no-such-repo" = { version = "latest", lazy = true }
EOF2
assert_not_contains "mise upgrade --dry-run 2>&1" "no-such-repo"
assert_contains "mise upgrade github:mise-test/no-such-repo --dry-run 2>&1" "no-such-repo"

# The same holds after an upgrade installs something: resolving the config again
# and pruning don't look the lazy tool up either.
mise uninstall dummy --all
mise install dummy@1.0.0
cat >"$MISE_SYSTEM_DIR/config.toml" <<'EOF2'
[tools]
dummy = "latest"
"github:mise-test/no-such-repo" = { version = "latest", lazy = true }
EOF2
assert_not_contains "mise upgrade --prune 2>&1" "Failed to resolve tool version list"
assert_contains "mise ls --installed dummy" "2.0.0"

# The lockfile keeps what it had for a tool the upgrade leaves alone, and never
# gains its unresolved request.
mise plugin install tiny
mkdir lockproj
cd lockproj || exit 1
cat >mise.toml <<'EOF2'
[settings]
lockfile = true
[tools]
dummy = "latest"
tiny = { version = "latest", lazy = true }
EOF2
touch mise.lock
mise uninstall dummy --all
mise install dummy@1.0.0 tiny
mise uninstall tiny --all
mise upgrade
assert_contains "mise ls --installed dummy" "2.0.0"
assert_contains "cat mise.lock" 'version = "2.0.0"'
assert_contains "cat mise.lock" "[[tools.tiny]]"
assert_not_contains "cat mise.lock" 'version = "latest"'

# With no entry for it, one is not invented from the unresolved request.
mise uninstall dummy --all
mise install dummy@1.0.0
rm mise.lock
touch mise.lock
mise upgrade
assert_contains "cat mise.lock" 'version = "2.0.0"'
assert_not_contains "cat mise.lock" "[[tools.tiny]]"
assert_not_contains "cat mise.lock" 'version = "latest"'
cd .. || exit 1

# A tool the upgrade leaves alone gets no minimum_release_age warning; naming it
# still shows one. jq has release dates, which the dummy backend lacks.
cat >"$MISE_SYSTEM_DIR/config.toml" <<'EOF'
[tools]
jq = { version = "latest", lazy = true }
EOF
assert_not_contains "mise upgrade --minimum-release-age 2019-01-01 --dry-run 2>&1" "ignored by minimum_release_age"
assert_contains "mise upgrade jq --minimum-release-age 2019-01-01 --dry-run 2>&1" "ignored by minimum_release_age"
