#!/usr/bin/env bash

assert "mise tasks add xxx -- echo 'running xxx'"
assert "mise generate task-stubs"
assert "./bin/xxx" "running xxx"

# Windows cannot execute the `#!/bin/sh` stub, so a launcher is written beside it. Generated here
# too, not only on Windows: stubs are committed, and the contributor who runs one on Windows is not
# the person who generated it.
assert_succeed "test -f bin/xxx.cmd"
# Both words are quoted, and for the same reason: each is interpolated into a cmd line, where a
# space splits it and `&` would end the command outright. Quoting is unconditional -- a quoted bare
# name still resolves through PATH, so there is no case where it costs anything.
assert_contains "cat bin/xxx.cmd" '"mise" run "xxx" %*'
# What marks the file as ours. Regeneration and cleanup both key off this rather than the shape of
# the command line, so that a hand-written batch file is never mistaken for a generated one.
assert_contains "cat bin/xxx.cmd" "rem generated by mise"

mkdir -p .mise/tasks/work/containers
cat >.mise/tasks/work/containers/_default <<'EOF'
#!/bin/sh
echo parent
EOF
cat >.mise/tasks/work/containers/pg <<'EOF'
#!/bin/sh
echo pg
EOF
cat >.mise/tasks/work/containers/redis <<'EOF'
#!/bin/sh
echo redis
EOF
chmod +x .mise/tasks/work/containers/{_default,pg,redis}

assert "mise generate task-stubs"
test -x bin/work/containers/_default
test -x bin/work/containers/pg
test -x bin/work/containers/redis
assert "bin/work/containers/_default" "parent"
assert "bin/work/containers/pg" "pg"
assert "bin/work/containers/redis" "redis"

# Launchers land inside nested stub directories as well.
assert_succeed "test -f bin/work/containers/pg.cmd"
assert_succeed "test -f bin/work/containers/_default.cmd"

# Regenerating walks that directory and refuses anything it did not write, so the launchers have to
# be recognised as generated -- without that, this second run fails.
assert "mise generate task-stubs"
assert "bin/work/containers/pg" "pg"

cat >.mise/tasks/legacy <<'EOF'
#!/bin/sh
echo legacy
EOF
chmod +x .mise/tasks/legacy
assert "mise generate task-stubs --dir legacy-bin"
test -f legacy-bin/legacy

# Preserve compatibility with stubs generated before the ownership marker.
# Generated stubs do not end with a newline, so reproduce the legacy output exactly.
printf '%s' '#!/bin/sh
exec mise run legacy "$@"' >legacy-bin/legacy

rm .mise/tasks/legacy
mkdir .mise/tasks/legacy
cat >.mise/tasks/legacy/_default <<'EOF'
#!/bin/sh
echo legacy
EOF
cat >.mise/tasks/legacy/child <<'EOF'
#!/bin/sh
echo child
EOF
chmod +x .mise/tasks/legacy/{_default,child}
assert "mise generate task-stubs --dir legacy-bin"
test -d legacy-bin/legacy
test -x legacy-bin/legacy/_default
test -x legacy-bin/legacy/child
assert "legacy-bin/legacy/_default" "legacy"
assert "legacy-bin/legacy/child" "child"

# The launcher goes with the stub it belonged to. Left behind, `legacy-bin/legacy.cmd` would keep
# running a task whose stub now lives at `legacy-bin/legacy/_default`.
test ! -e legacy-bin/legacy.cmd
test -f legacy-bin/legacy/_default.cmd

# Removing the nested task collapses the generated directory back to a leaf stub.
cat >legacy-bin/legacy/user-script <<'EOF'
#!/bin/sh
exec custom-tool run user-task "$@"
EOF
mv .mise/tasks/legacy/_default .mise/tasks/legacy-task
rm .mise/tasks/legacy/child
rmdir .mise/tasks/legacy
mv .mise/tasks/legacy-task .mise/tasks/legacy
assert_fail_contains \
  "mise generate task-stubs --dir legacy-bin" \
  "legacy-bin/legacy/user-script is not a generated task stub"
test -f legacy-bin/legacy/user-script
rm legacy-bin/legacy/user-script
assert "mise generate task-stubs --dir legacy-bin"
test -f legacy-bin/legacy
test ! -d legacy-bin/legacy
assert "legacy-bin/legacy" "legacy"

mkdir -p blocked-bin
echo "user-owned" >blocked-bin/work
assert_fail_contains \
  "mise generate task-stubs --dir blocked-bin" \
  "blocked-bin/work is not a directory"
test ! -e blocked-bin/xxx
assert "cat blocked-bin/work" "user-owned"

mkdir -p symlink-bin
echo "user-owned" >symlink-target
ln -s ../symlink-target symlink-bin/xxx
assert_fail_contains \
  "mise generate task-stubs --dir symlink-bin" \
  "symlink-bin/xxx is a symbolic link"
assert "cat symlink-target" "user-owned"
test -L symlink-bin/xxx
test ! -e symlink-bin/work

# `bin/<task>.cmd` is a plausible name for a script a project already keeps, and nothing about the
# name says mise owns it. Generation stops rather than overwriting one, and stops during validation,
# so no stub is written either.
mkdir -p owned-bin
printf '@echo off\r\necho mine\r\n' >owned-bin/xxx.cmd
assert_fail_contains \
  "mise generate task-stubs --dir owned-bin" \
  "owned-bin/xxx.cmd is not a generated launcher"
assert_contains "cat owned-bin/xxx.cmd" "echo mine"
test ! -e owned-bin/xxx

mkdir -p relocated-blocked-bin/work/containers
cat >relocated-blocked-bin/work/containers/_default <<'EOF'
#!/bin/sh
exec custom-tool run work:containers "$@"
EOF
assert_fail_contains \
  "mise generate task-stubs --dir relocated-blocked-bin" \
  "relocated-blocked-bin/work/containers/_default is not a generated task stub"
assert_contains "cat relocated-blocked-bin/work/containers/_default" "exec custom-tool run work:containers"
test ! -e relocated-blocked-bin/xxx
