#!/usr/bin/env bash

# fnox is never asked for a value unless a task that lists it actually runs.

mkdir -p "$HOME/bin"
printf '#!/usr/bin/env bash\nexec python3 "%s" "$@"\n' "$TEST_ROOT/helpers/scripts/fnox_stub.py" >"$HOME/bin/fnox"
chmod +x "$HOME/bin/fnox"
export PATH="$HOME/bin:$PATH"
export FNOX_STUB_LOG="$PWD/fnox-calls.jsonl"
export FNOX_AGE_KEY=ambient-age SIGNING_KEY=ambient-sign

cat >mise.toml <<'TOML'
[secrets.fnox]

[tasks.build]
run = "true"

[tasks.deploy]
depends = ["build"]
secrets = ["DEPLOY_KEY", "DATABASE_URL", "PEM_KEY"]
sources = ["src.txt"]
outputs = ["deploy.out"]
run = "printf x >>runs.out; touch deploy.out"
TOML
echo a >src.txt

resolves() {
  if [[ -f fnox-calls.jsonl ]]; then
    jq -s '[.[]|select(.argv|index("--keys"))]|length' fnox-calls.jsonl
  else
    echo 0
  fi
}
no_new_resolution() {
  [[ "$(resolves)" == "$1" ]] || fail "unexpected fnox resolution: $(resolves) != $1"
}

mise run build </dev/null
no_new_resolution 0
assert_contains "mise run -n deploy </dev/null 2>&1" "secrets: DATABASE_URL, DEPLOY_KEY, PEM_KEY"
[[ ! -e fnox-calls.jsonl ]] || fail "a dry run must not run fnox at all"
mise hook-env -s bash >/dev/null
mise env >/dev/null
no_new_resolution 0
assert "mise x -- sh -c 'printf %s \"\${DEPLOY_KEY-unset}\"'" "unset"
no_new_resolution 0

# the first run resolves; the second finds its sources fresh and does not
mise run deploy </dev/null >/dev/null 2>&1
no_new_resolution 1
mise run deploy </dev/null >/dev/null 2>&1
no_new_resolution 1
assert "cat runs.out" "x"

# refused launchers fail before anything runs
assert_fail_contains "MISE_DAEMON_TASK=1 mise run --force deploy </dev/null" "pitchfork daemon"
assert_fail_contains "__MISE_SECRETS_DENIED=hook mise run --force deploy </dev/null" "a mise hook"
no_new_resolution 1

# a watch_files run hook is a refused launcher too
mise_bin="$(command -v mise)"
cat >mise.toml <<TOML
[secrets.fnox]

[[watch_files]]
patterns = ["watched.txt"]
run = "$mise_bin run --force deploy </dev/null"

[tasks.deploy]
secrets = ["DEPLOY_KEY"]
run = "true"
TOML
before=$(resolves)
# adopt only the session state: the rest of the output rewrites PATH to another mise
eval "$(mise hook-env -s bash | grep -E '^export __MISE_(DIFF|SESSION)=')"
sleep 1
touch watched.txt
output=$(mise hook-env -s bash 2>&1 || true)
grep -q "started by watch_files" <<<"$output" || fail "expected the watch_files refusal, got: $output"
no_new_resolution "$before"

# a shell hook runs in the user's own shell; the emitted snippet marks it, so `mise run` refuses,
# even after a nested hook-env (what a `cd` in the script triggers)
cat >mise.toml <<TOML
[secrets.fnox]

[hooks.enter]
shell = "bash"
script = 'if [ -z "\${NESTED-}" ]; then export NESTED=1; eval "\$($mise_bin hook-env -s bash --force)"; fi; $mise_bin run --force deploy </dev/null 2>&1 || true'

[tasks.deploy]
secrets = ["DEPLOY_KEY"]
run = "true"
TOML
before=$(resolves)
(
  eval "$(mise hook-env -s bash)"
  cd ~ || exit 1
  eval "$(mise hook-env -s bash)"
  cd ~/workdir || exit 1
  mise hook-env -s bash >"$HOME/hook-out.sh" 2>&1
)
grep -q "shell_hook" "$HOME/hook-out.sh" || fail "the hook snippet does not mark the shell"
# shellcheck source=/dev/null
hook_run=$( (source "$HOME/hook-out.sh") 2>&1 || true)
grep -q "started by a mise shell hook" <<<"$hook_run" || fail "expected the shell hook refusal, got: $hook_run"
grep -q "left __MISE_SECRETS_DENIED set" <<<"$hook_run" || fail "expected the stale mark hint, got: $hook_run"
no_new_resolution "$before"

# hook-env never clears or sets the mark itself
marked=$(__MISE_SECRETS_DENIED=shell_hook mise hook-env -s bash --force 2>&1 || true)
if grep -q "__MISE_SECRETS_DENIED" <<<"$marked"; then fail "hook-env touched the mark: $marked"; fi
