#!/usr/bin/env bash

# Expected failures are checked one by one, so this script deliberately avoids
# a global `set -e`.

set -o pipefail

fail() {
  printf 'FAIL: %s\n' "$1" >&2
  exit 1
}

SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)" \
  || fail "cannot resolve script directory"
cd "$SCRIPT_DIR" || fail "cannot enter script directory"

test -n "${JDK17_HOME:-}" || fail "set JDK17_HOME to a JDK 17 root"
JAVA="$JDK17_HOME/bin/java"
JAVAC="$JDK17_HOME/bin/javac"
for tool in "$JAVA" "$JAVAC"; do
  test -x "$tool" || fail "missing executable: $tool"
done

JAVA_VERSION="$("$JAVA" -version 2>&1)" || fail "java -version failed"
JAVAC_VERSION="$("$JAVAC" -version 2>&1)" || fail "javac -version failed"
grep -Eq 'version "17([.+-][^"]*)?"' <<<"$JAVA_VERSION" \
  || fail "java is not Java 17"
grep -Eq '^javac 17([.+-].*)?$' <<<"$JAVAC_VERSION" \
  || fail "javac is not Java 17"
printf '%s\n' "$JAVA_VERSION" "$JAVAC_VERSION"

TMP_BASE="$(CDPATH= cd -- "${TMPDIR:-/tmp}" && pwd -P)" \
  || fail "cannot resolve temporary directory"
LAB_OUT="$(mktemp -d "$TMP_BASE/java-collections-stream.XXXXXX")" \
  || fail "mktemp failed"
case "$LAB_OUT" in
  "$TMP_BASE"/java-collections-stream.*) ;;
  *) fail "unsafe temporary path: $LAB_OUT" ;;
esac
cleanup() {
  if ! rm -rf -- "$LAB_OUT"; then
    printf 'FAIL: cannot clean temporary directory: %s\n' "$LAB_OUT" >&2
    trap - EXIT
    exit 1
  fi
}
trap cleanup EXIT

"$JAVAC" --release 17 -Xlint:all -Werror \
  -d "$LAB_OUT" CollectionsStreamLab.java \
  || fail "strict compilation failed"

NORMAL_OUT="$("$JAVA" -cp "$LAB_OUT" CollectionsStreamLab normal)" \
  || fail "normal mode failed"
for expected in \
  'deduplicated=[CREATED, PAID, SHIPPED]' \
  'ownership=source:3 view:3 snapshot:2' \
  'iterator-remove=[CREATED, PAID]' \
  'lazy-before-terminal=0' \
  'lazy-after-terminal=2 result=[paid, shipped]' \
  'merged-by-customer={alice=1500, bob=800}' \
  'atomic-merge=CREATED:2 PAID:1 SHIPPED:1' \
  'spliterator=ORDERED:true DISTINCT:true' \
  'associative-sum=sequential:50005000 parallel:50005000'; do
  grep -Fqx "$expected" <<<"$NORMAL_OUT" \
    || fail "normal output missing: $expected"
done
printf '%s\n' "$NORMAL_OUT"

assert_failure() {
  local mode="$1"
  local expected_status="$2"
  local expected_line="$3"
  "$JAVA" -cp "$LAB_OUT" CollectionsStreamLab "$mode" \
    >"$LAB_OUT/$mode.out" 2>"$LAB_OUT/$mode.err"
  local status=$?
  test "$status" -eq "$expected_status" \
    || fail "$mode returned $status, expected $expected_status"
  grep -Eq "$expected_line" "$LAB_OUT/$mode.err" \
    || fail "$mode did not report the expected diagnosis"
  cat "$LAB_OUT/$mode.err"
}

assert_failure cme 2 '^mode=cme exception=ConcurrentModificationException$'
assert_failure duplicate-key 3 '^mode=duplicate-key exception=IllegalStateException$'
assert_failure reuse-stream 4 '^mode=reuse-stream first-count=2 exception=IllegalStateException$'
assert_failure bad-reduction 5 '^mode=bad-reduction associative=false left=13 right=17 sequential=-78 parallel=-?[0-9]+$'

printf '%s\n' 'PASS'
