#!/usr/bin/env bats

setup() {
    load 'test_helper/common_setup'
    _common_setup
}
teardown() {
    _common_teardown
}

@test "auto-batch large file lists" {
    cat <<EOF > hk.pkl
amends "$PKL_PATH/Config.pkl"
hooks {
    ["check"] {
        steps {
            ["count-files"] {
                check = "echo batch >> batches.log; echo 'Processing {{files}}' | wc -w"
            }
        }
    }
}
EOF

    # Make the rendered sh -c argument exceed Linux's 128 KiB MAX_ARG_STRLEN.
    # This remains below ARG_MAX / 2 on a typical glibc system, which is the
    # regression case for discussion #1061.
    for i in {1..1200}; do
        dir="very/long/directory/path/number/$i/with/many/levels/to/increase/path/length"
        mkdir -p "$dir"
        echo "test" > "$dir/file_with_very_long_name_to_increase_arg_size_$i.txt"
    done

    # Run check and verify it completes successfully without "Argument list too long" errors
    run hk check
    assert_success

    # Linux must split the command at MAX_ARG_STRLEN. Other platforms have
    # different command-line limits, so the batch count is platform-specific.
    if [[ "$OSTYPE" == "linux"* ]]; then
        [ "$(wc -l < batches.log)" -gt 1 ]
    fi
}

@test "auto-batch does not break small file lists" {
    cat <<EOF > hk.pkl
amends "$PKL_PATH/Config.pkl"
hooks {
    ["check"] {
        steps {
            ["echo-files"] {
                check = "echo {{files}}"
            }
        }
    }
}
EOF

    # Create a small number of files
    for i in {1..10}; do
        echo "test" > "file$i.txt"
    done

    run hk check
    assert_success

    # All files should be passed in a single command (no batching needed)
    assert_output --partial "file1.txt"
    assert_output --partial "file10.txt"
}

@test "auto-batch does not split steps that don't reference {{files}}" {
    # Regression test: previously hk would auto-batch any step on a large file
    # list based on the *file list* size, even if the run command never
    # interpolated `{{files}}`. With render-based sizing, a static command
    # should run as a single job regardless of how many files match.
    cat <<EOF > hk.pkl
amends "$PKL_PATH/Config.pkl"
hooks {
    ["check"] {
        steps {
            ["static-message"] {
                check = "echo hello world"
            }
        }
    }
}
EOF

    # Create enough files (with long paths) that the *file-list* expansion
    # would blow past ARG_MAX/2 and force batching under the old logic.
    for i in {1..1000}; do
        dir="very/long/directory/path/number/$i/with/many/levels/to/increase/path/length"
        mkdir -p "$dir"
        echo "test" > "$dir/file_with_very_long_name_to_increase_arg_size_$i.txt"
    done

    run hk check --all
    assert_success
    # Each batch produces its own "N files – ... – <command>" progress line;
    # one such line means the step ran as a single job.
    run bash -c "hk check --all 2>&1 | grep -Ec 'files –.*– echo hello world' || true"
    assert_output "1"
}

@test "auto-batch with fix command" {
    cat <<EOF > hk.pkl
amends "$PKL_PATH/Config.pkl"
hooks {
    ["fix"] {
        fix = true
        steps {
            ["count"] {
                fix = "echo 'Fixing {{files}}'"
            }
        }
    }
}
EOF

    # Create many files
    for i in {1..100}; do
        echo "test" > "file$i.txt"
    done

    run hk fix
    assert_success
    assert_output --partial "Fixing"
}

@test "focused check is rebatched after file-list filtering" {
    cat <<EOF > hk.pkl
amends "$PKL_PATH/Config.pkl"
hooks {
    ["check"] {
        steps {
            ["focused"] {
                check_list_files = "find very -type f; exit 1"
                check = "echo batch >> batches.log; echo '{{files}}' > /dev/null"
                check_failed_files = true
            }
        }
    }
}
EOF

    # The listing command is short, while the focused command exceeds Linux's
    # per-argument limit and must be sized again after the files are filtered.
    for i in {1..1200}; do
        dir="very/long/directory/path/number/$i/with/many/levels/to/increase/path/length"
        mkdir -p "$dir"
        echo "test" > "$dir/file_with_very_long_name_to_increase_arg_size_$i.txt"
    done

    run hk check --all
    assert_failure
    assert_output --partial "file-listing check failed but focused check succeeded"
    if [[ "$OSTYPE" == "linux"* ]]; then
        [ "$(wc -l < batches.log)" -gt 1 ]
    fi
}

@test "focused re-batch errors preserve listing diagnostics" {
    if [[ "$OSTYPE" != "linux"* ]]; then
        skip "Linux MAX_ARG_STRLEN behavior"
    fi

    max_arg_strlen=$(( $(getconf PAGESIZE) * 32 ))
    oversized=$(printf '%*s' "$max_arg_strlen" '' | tr ' ' x)
    cat <<EOF > hk.pkl
amends "$PKL_PATH/Config.pkl"
hooks {
    ["check"] {
        steps {
            ["focused"] {
                check_list_files = "sh -c 'echo bad.txt; echo listing-diagnostic >&2; exit 1'"
                check = "echo $oversized {{files}}"
                check_failed_files = true
            }
        }
    }
}
EOF
    echo "bad" > bad.txt

    run hk check --all
    assert_failure
    assert_output --partial "listing-diagnostic"
    assert_output --partial "command-line limit"
}
