#!/usr/bin/env bash

export MISE_EXPERIMENTAL=1
export AFFECTED_LOG="$PWD/affected.log"

cat <<'EOF' >.gitignore
affected.log
Cargo.lock
EOF

cat <<'EOF' >mise.toml
monorepo_root = true

[monorepo]
config_roots = ["crates/*"]

[task_config]
global_inputs = ["crates/core/global.txt"]
EOF

cat <<'EOF' >Cargo.toml
[workspace]
members = ["crates/app", "crates/core", "crates/other"]
resolver = "2"
EOF

mkdir -p crates/app/src crates/core/src crates/other/src
cat <<'EOF' >crates/app/Cargo.toml
[package]
name = "app"
version = "0.1.0"

[dependencies]
core = { path = "../core" }
EOF

for crate in core other; do
  cat <<EOF >"crates/$crate/Cargo.toml"
[package]
name = "$crate"
version = "0.1.0"
EOF
done

for crate in app core other; do
  cat <<EOF >"crates/$crate/mise.toml"
[tasks.build]
run = "echo $crate >> \"\$AFFECTED_LOG\""
EOF
  echo "$crate" >"crates/$crate/src/lib.rs"
done
cat <<'EOF' >>crates/app/mise.toml
depends = ["//crates/other:prepare"]
EOF
cat <<'EOF' >>crates/other/mise.toml

[tasks.prepare]
run = "echo other-prepare >> \"$AFFECTED_LOG\""
EOF
echo initial >crates/core/global.txt

git init -q
git config user.email test@example.com
git config user.name Test
git add .
git commit -qm initial

echo changed >>crates/core/src/lib.rs
git add .
git commit -qm core-change
assert_json "mise run --affected --affected-json build" '{
  "base": "HEAD~1",
  "head": "HEAD",
  "projects": [
    {
      "id": "cargo:app",
      "root": "crates/app",
      "reasons": [
        {
          "type": "dependent",
          "dependency": "cargo:core"
        }
      ]
    },
    {
      "id": "cargo:core",
      "root": "crates/core",
      "reasons": [
        {
          "type": "changed-path",
          "path": "crates/core/src/lib.rs"
        }
      ]
    }
  ],
  "tasks": [
    {
      "name": "//crates/app:build",
      "projects": ["cargo:app"]
    },
    {
      "name": "//crates/core:build",
      "projects": ["cargo:core"]
    }
  ]
}'
assert "test ! -e affected.log"
output=$(mise run --affected --affected-explain --jobs 1 build)
assert_contains "echo \"$output\"" "Affected projects (HEAD~1...HEAD):"
assert_contains "echo \"$output\"" "changed path: crates/core/src/lib.rs"
assert_contains "echo \"$output\"" "depends on affected project: cargo:core"
assert_contains "echo \"$output\"" "Affected tasks:"
assert_contains "echo \"$output\"" "affected project: cargo:app"
assert "sort affected.log" $'app\ncore\nother-prepare'

: >affected.log
echo changed >>crates/app/src/lib.rs
git add .
git commit -qm app-change
mise run --affected --affected-base HEAD~1 --affected-head HEAD --jobs 1 build
assert "sort affected.log" $'app\nother-prepare'

: >affected.log
echo changed >>crates/core/global.txt
git add .
git commit -qm global-change
mise run --affected --jobs 1 build
assert "sort affected.log" $'app\ncore\nother\nother-prepare'

: >affected.log
mise run --affected --affected-base HEAD --affected-head HEAD --jobs 1 build
assert "cat affected.log" ""

# A pnpm lockfile in a workspace without Node projects falls back to ordinary
# changed-path mapping instead of being swallowed as an empty provider result.
cat <<'EOF' >pnpm-lock.yaml
lockfileVersion: '9.0'
EOF
git add pnpm-lock.yaml
git commit -qm add-unrelated-pnpm-lockfile
cat <<'EOF' >pnpm-lock.yaml
lockfileVersion: '9.1'
EOF
git add pnpm-lock.yaml
git commit -qm change-unrelated-pnpm-lockfile
: >affected.log
output=$(mise run --affected --affected-explain --jobs 1 build)
assert_contains "echo \"$output\"" "workspace-global path: pnpm-lock.yaml"
assert "sort affected.log" $'app\ncore\nother\nother-prepare'

mkdir node-case
cd node-case
export AFFECTED_LOG="$PWD/affected.log"

cat <<'EOF' >.gitignore
affected.log
EOF
cat <<'EOF' >mise.toml
monorepo_root = true

[monorepo]
config_roots = ["packages/*"]
EOF
cat <<'EOF' >pnpm-workspace.yaml
packages:
  - packages/*
EOF
mkdir -p packages/app packages/lib packages/other
cat <<'EOF' >packages/app/package.json
{"name":"app","dependencies":{"lib":"workspace:*"}}
EOF
cat <<'EOF' >packages/lib/package.json
{"name":"lib"}
EOF
cat <<'EOF' >packages/other/package.json
{"name":"other"}
EOF
for package in app lib other; do
  cat <<EOF >"packages/$package/mise.toml"
[tasks.build]
run = "echo $package >> \"\$AFFECTED_LOG\""
EOF
done
cat <<'EOF' >pnpm-lock.yaml
lockfileVersion: '9.0'
importers:
  packages/app: {}
  packages/lib:
    dependencies:
      bar: {specifier: ^1.0.0, version: 1.0.0}
  packages/other: {}
packages:
  bar@1.0.0: {}
snapshots:
  bar@1.0.0: {}
EOF

git init -q
git config user.email test@example.com
git config user.name Test
git add .
git commit -qm initial
sed -i 's/1\.0\.0/2.0.0/g' pnpm-lock.yaml
git add pnpm-lock.yaml
git commit -qm lockfile-change

output=$(mise run --affected --affected-explain --jobs 1 build)
assert_contains "echo \"$output\"" "lockfile change: pnpm-lock.yaml"
assert_contains "echo \"$output\"" "depends on affected project: node:lib"
assert "sort affected.log" $'app\nlib'
