#!/usr/bin/env bash
set -uo pipefail

DIR="tests/fixtures"
MAX_LINE_LENGTH=120
PASS=0
FAIL=0
TOTAL=0
ERRORS=""

get_cpu_count() {
    if command -v nproc >/dev/null 2>&1; then
        nproc
    elif command -v getconf >/dev/null 2>&1; then
        getconf _NPROCESSORS_ONLN
    elif command -v sysctl >/dev/null 2>&1; then
        sysctl -n hw.ncpu
    else
        echo "4"
    fi
}

JOBS="${PHEW_FIXTURE_JOBS:-$(get_cpu_count)}"
if ! [[ "$JOBS" =~ ^[0-9]+$ ]] || [ "$JOBS" -lt 1 ]; then
    JOBS=1
fi

TMP_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/phew_check.XXXXXX")"
trap 'rm -rf "$TMP_ROOT"' EXIT

if ! cargo build -q; then
    echo "❌ cargo build failed"
    exit 1
fi

BIN="${PHEW_FIXTURE_BIN:-target/debug/phew}"
if [ ! -x "$BIN" ]; then
    echo "❌ formatter binary not found: $BIN"
    exit 1
fi

shopt -s nullglob

check_expected_quality() {
    local expected="$1"
    local name line_no line length lint_out lint_code

    name=$(basename "$expected")

    if grep -n $'\t' "$expected" >/dev/null; then
        ERRORS+="  ✗ $name (expected contains tab characters)\n"
        FAIL=$((FAIL + 1))
    fi

    if grep -nE '[[:blank:]]$' "$expected" >/dev/null; then
        ERRORS+="  ✗ $name (expected contains trailing whitespace)\n"
        FAIL=$((FAIL + 1))
    fi

    line_no=0
    while IFS= read -r line || [ -n "$line" ]; do
        line_no=$((line_no + 1))
        length=${#line}
        if [ "$length" -gt "$MAX_LINE_LENGTH" ]; then
            ERRORS+="  ✗ $name:$line_no (expected line length $length > $MAX_LINE_LENGTH)\n"
            FAIL=$((FAIL + 1))
        fi
    done <"$expected"

    if [[ "$expected" == *.php ]] && command -v php >/dev/null 2>&1; then
        lint_out=$(php -l "$expected" 2>&1)
        lint_code=$?
        if [ "$lint_code" -ne 0 ]; then
            lint_out=$(printf '%s' "$lint_out" | tr '\n\t' '  ' | sed 's/[[:space:]]\+/ /g; s/^ //; s/ $//')
            ERRORS+="  ✗ $name (expected php -l failed: $lint_out)\n"
            FAIL=$((FAIL + 1))
        fi
    fi
}

for expected in "$DIR"/expected/*; do
    name=$(basename "$expected")
    check_expected_quality "$expected"
    if [ ! -f "$DIR/input/$name" ]; then
        ERRORS+="  ⚠ orphan expected (no input): $name\n"
        FAIL=$((FAIL + 1))
        TOTAL=$((TOTAL + 1))
    fi
done

check_fixture() {
    local input="$1"
    local name expected actual_file idem_file err_file result_file err_msg exit_code

    name=$(basename "$input")
    expected="$DIR/expected/$name"
    actual_file="$TMP_ROOT/actual_$name"
    idem_file="$TMP_ROOT/idem_$name"
    err_file="$TMP_ROOT/err_$name"
    result_file="$TMP_ROOT/result_$name"

    if [ ! -f "$expected" ]; then
        printf 'missing_expected\t%s\n' "$name" >"$result_file"
        return
    fi

    "$BIN" "$input" >"$actual_file" 2>"$err_file"
    exit_code=$?
    if [ "$exit_code" -ne 0 ]; then
        err_msg=$(tr '\n\t' '  ' <"$err_file" | sed 's/[[:space:]]\+/ /g; s/^ //; s/ $//')
        printf 'exit_error\t%s\t%s\t%s\n' "$name" "$exit_code" "$err_msg" >"$result_file"
        return
    fi

    if ! diff -q "$expected" "$actual_file" >/dev/null 2>&1; then
        printf 'diff\t%s\n' "$name" >"$result_file"
        return
    fi

    "$BIN" "$actual_file" >"$idem_file" 2>/dev/null
    exit_code=$?
    if [ "$exit_code" -ne 0 ]; then
        printf 'idem_exit_error\t%s\t%s\n' "$name" "$exit_code" >"$result_file"
        return
    fi

    if diff -q "$actual_file" "$idem_file" >/dev/null 2>&1; then
        printf 'pass\t%s\n' "$name" >"$result_file"
    else
        printf 'not_idempotent\t%s\n' "$name" >"$result_file"
    fi
}

inputs=("$DIR"/input/*)
TOTAL=$((TOTAL + ${#inputs[@]}))

export DIR BIN TMP_ROOT
export -f check_fixture

if [ ${#inputs[@]} -gt 0 ]; then
    for input in "${inputs[@]}"; do
        printf '%s\0' "$input"
    done | xargs -0 -n1 -P "$JOBS" bash -c 'check_fixture "$1"' _
    xargs_status=$?
    if [ "$xargs_status" -ne 0 ]; then
        echo "❌ fixture workers failed (xargs exit $xargs_status)"
        exit 1
    fi
fi

results=("$TMP_ROOT"/result_*)
if [ "${#results[@]}" -ne "${#inputs[@]}" ]; then
    ERRORS+="  ✗ internal error: expected ${#inputs[@]} result files, got ${#results[@]}\n"
    FAIL=$((FAIL + 1))
fi

for result in "${results[@]}"; do
    IFS=$'\t' read -r status name value details <"$result"
    case "$status" in
        pass)
            PASS=$((PASS + 1))
            ;;
        missing_expected)
            ERRORS+="  ⚠ missing expected: $name\n"
            FAIL=$((FAIL + 1))
            ;;
        diff)
            ERRORS+="  ✗ $name (output differs from expected)\n"
            FAIL=$((FAIL + 1))
            ;;
        not_idempotent)
            ERRORS+="  ✗ $name (not idempotent — second pass differs)\n"
            FAIL=$((FAIL + 1))
            ;;
        idem_exit_error)
            ERRORS+="  ✗ $name (idempotence run failed with exit $value)\n"
            FAIL=$((FAIL + 1))
            ;;
        exit_error)
            ERRORS+="  ✗ $name (exit $value: $details)\n"
            FAIL=$((FAIL + 1))
            ;;
        *)
            ERRORS+="  ✗ $name (unknown fixture status: $status)\n"
            FAIL=$((FAIL + 1))
            ;;
    esac
done

echo ""
if [ -n "$ERRORS" ]; then
    echo "Failures:"
    echo -e "$ERRORS"
fi

echo "Results:"
echo "  Total:  $TOTAL"
echo "  Passed: $PASS"
echo "  Failed: $FAIL"

if [ "$FAIL" -eq 0 ]; then
    echo ""
    echo "✅ All fixtures passed!"
else
    exit 1
fi
