#!/usr/bin/env sh
set -eu

ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
"$ROOT/bin/check-conventions"
# tui/bin/test runs the same gate, so mark it done to keep the root gate from
# running it twice.
OMAIRC_CONVENTIONS_RAN=1
export OMAIRC_CONVENTIONS_RAN
if command -v go >/dev/null 2>&1; then
  "$ROOT/tui/bin/test"
else
  echo "Skipping tui/bin/test: go is not on PATH." >&2
fi
python3 -m unittest -v tests.test_derive_build_versions tests.test_omarchy_qt_binary
TEST_STATE="$(mktemp -d "${TMPDIR:-/tmp}/omairc-tests.XXXXXX")"
STALE_VERSION_HEADER="$ROOT/omaircversion.h"
STALE_VERSION_BACKUP=""
if [ -f "$STALE_VERSION_HEADER" ]; then
  STALE_VERSION_BACKUP="$TEST_STATE/omaircversion.h.saved"
  cp -- "$STALE_VERSION_HEADER" "$STALE_VERSION_BACKUP"
fi

cleanup() {
  if [ -n "$STALE_VERSION_BACKUP" ]; then
    mv -- "$STALE_VERSION_BACKUP" "$STALE_VERSION_HEADER"
  else
    rm -f -- "$STALE_VERSION_HEADER"
  fi
  rm -rf -- "$TEST_STATE"
}
trap cleanup EXIT HUP INT TERM

# An in-source build, such as Arch makepkg, leaves this header next to the
# .pro file. Shadow builds must still compile the copy written for OUT_PWD.
cat > "$STALE_VERSION_HEADER" << 'EOF'
#ifndef OMAIRC_VERSION_H
#define OMAIRC_VERSION_H
#define OMAIRC_VERSION "stale-insource"
#endif
EOF

if command -v qmake6 >/dev/null 2>&1; then
  QMAKE=qmake6
elif command -v qmake >/dev/null 2>&1 && qmake -query QT_VERSION | grep -q '^6\.'; then
  QMAKE=qmake
else
  echo "A Qt 6 qmake (qmake6) is required to test omairc." >&2
  exit 1
fi

JOBS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1)"

omairc_binary() {
  if [ -x "$ROOT/build/omairc" ]; then
    printf '%s\n' "$ROOT/build/omairc"
  elif [ -x "$ROOT/build/omairc.app/Contents/MacOS/omairc" ]; then
    printf '%s\n' "$ROOT/build/omairc.app/Contents/MacOS/omairc"
  else
    echo "Could not find omairc binary under $ROOT/build." >&2
    exit 1
  fi
}

"$ROOT/bin/build"
OMAIRC_BIN="$(omairc_binary)"

VERSION="$("$ROOT/bin/version")"
got="$(DISPLAY= "$OMAIRC_BIN" --version)"
test "$got" = "omairc $VERSION" || {
  echo "--version must print exactly omairc $VERSION" >&2
  printf 'got: %s\n' "$got" >&2
  exit 1
}

BUILD_OVERRIDE_DIR="$ROOT/build-version-override"
rm -rf "$BUILD_OVERRIDE_DIR"
mkdir -p "$BUILD_OVERRIDE_DIR"
OVERRIDE_VERSION="${VERSION}+main.gdeadbeef"
cd "$BUILD_OVERRIDE_DIR"
"$QMAKE" "OMAIRC_BUILD_VERSION=$OVERRIDE_VERSION" "$ROOT/omairc.pro"
make -j"$JOBS"
OVERRIDE_BIN="$BUILD_OVERRIDE_DIR/omairc"
if [ ! -x "$OVERRIDE_BIN" ]; then
  OVERRIDE_BIN="$BUILD_OVERRIDE_DIR/omairc.app/Contents/MacOS/omairc"
fi
HEADER="$BUILD_OVERRIDE_DIR/omaircversion.h"
test -f "$HEADER" || {
  echo "expected generated header at $HEADER" >&2
  exit 1
}
grep -Fq "\"$OVERRIDE_VERSION\"" "$HEADER" || {
  echo "omaircversion.h must embed OMAIRC_BUILD_VERSION" >&2
  exit 1
}
override_got="$(DISPLAY= "$OVERRIDE_BIN" --version)"
test "$override_got" = "omairc $OVERRIDE_VERSION" || {
  echo "OMAIRC_BUILD_VERSION must appear in omairc --version" >&2
  printf 'got: %s\n' "$override_got" >&2
  exit 1
}
HEADER_MTIME="$(stat -c %Y "$HEADER" 2>/dev/null || stat -f %m "$HEADER")"
sleep 1
make -j"$JOBS" omairc
HEADER_MTIME_AFTER="$(stat -c %Y "$HEADER" 2>/dev/null || stat -f %m "$HEADER")"
test "$HEADER_MTIME" = "$HEADER_MTIME_AFTER" || {
  echo "unchanged OMAIRC_BUILD_VERSION must not rewrite omaircversion.h" >&2
  exit 1
}
cd "$ROOT"

assert_not_version_line() {
  first_line=$(printf '%s\n' "$1" | head -n 1)
  case "$first_line" in
    omairc\ [0-9]*)
      echo "$2 printed the version line." >&2
      exit 1
      ;;
  esac
}

is_json_object() {
  case "$1" in
    \{*) return 0 ;;
    *) return 1 ;;
  esac
}

set +e
HELP_OUTPUT="$(DISPLAY= "$OMAIRC_BIN" --help 2>&1)"
HELP_STATUS=$?
set -e
if [ "$HELP_STATUS" -ne 0 ]; then
  echo "omairc --help failed." >&2
  exit 1
fi
assert_not_version_line "$HELP_OUTPUT" "omairc --help"
if is_json_object "$HELP_OUTPUT"; then
  echo "omairc --help must not print JSON." >&2
  exit 1
fi
for token in connections list status send read names conversations raise --demo-server --version; do
  printf '%s\n' "$HELP_OUTPUT" | grep -Fq -- "$token" || {
    echo "omairc --help must mention $token" >&2
    exit 1
  }
done

for command in connections list status send read names conversations raise; do
  set +e
  COMMAND_HELP="$(DISPLAY= "$OMAIRC_BIN" "$command" --help 2>&1)"
  COMMAND_STATUS=$?
  set -e
  if [ "$COMMAND_STATUS" -ne 0 ]; then
    echo "omairc $command --help failed." >&2
    exit 1
  fi
  if is_json_object "$COMMAND_HELP"; then
    echo "omairc $command --help must not print JSON." >&2
    exit 1
  fi
done

set +e
SEND_HELP="$(DISPLAY= "$OMAIRC_BIN" send --help 2>&1)"
SEND_HELP_STATUS=$?
set -e
if [ "$SEND_HELP_STATUS" -ne 0 ]; then
  echo "omairc send --help failed." >&2
  exit 1
fi
assert_not_version_line "$SEND_HELP" "omairc send --help"
if is_json_object "$SEND_HELP"; then
  echo "omairc send --help must not print JSON." >&2
  exit 1
fi
printf '%s\n' "$SEND_HELP" | grep -Fq -- "Usage: omairc send" || {
  echo "omairc send --help must print send usage." >&2
  exit 1
}

set +e
SEND_TEXT="$(DISPLAY= "$OMAIRC_BIN" send '#c' --help 2>&1)"
set -e
printf '%s\n' "$SEND_TEXT" | grep -Fq -- "Usage: omairc send" && {
  echo "omairc send '#c' --help must not print the send help page." >&2
  exit 1
}

if [ "$(uname -s)" != Darwin ]; then
  COMPLETION="$ROOT/data/bash-completion/omairc"
  COMPREPLY_TEXT="$(bash -c '
    source "$1"
    COMP_WORDS=(omairc "")
    COMP_CWORD=1
    _omairc
    printf "%s\n" "${COMPREPLY[@]}"
  ' bash "$COMPLETION")"
  printf '%s\n' "$COMPREPLY_TEXT" | grep -Fxq send || {
    echo "bash completion at the first token must include send." >&2
    exit 1
  }
  printf '%s\n' "$COMPREPLY_TEXT" | grep -Fxq -- --help || {
    echo "bash completion at the first token must include --help." >&2
    exit 1
  }
  HELP_COMPREPLY_TEXT="$(bash -c '
    source "$1"
    COMP_WORDS=(omairc help "s")
    COMP_CWORD=2
    _omairc
    printf "%s\n" "${COMPREPLY[@]}"
  ' bash "$COMPLETION")"
  printf '%s\n' "$HELP_COMPREPLY_TEXT" | grep -Fxq send || {
    echo "bash completion for help must include send." >&2
    exit 1
  }
  printf '%s\n' "$HELP_COMPREPLY_TEXT" | grep -Fxq status || {
    echo "bash completion for help must include status." >&2
    exit 1
  }
  for token in connections list status send read names conversations raise; do
    printf '%s\n' "$HELP_OUTPUT" | grep -Fq -- "$token" || continue
    grep -Fq -- "$token" "$COMPLETION" || {
      echo "completion file must mention control verb $token from --help." >&2
      exit 1
    }
  done
fi

set +e
CLI_OUTPUT="$("$OMAIRC_BIN" send '#channel' please use --version 2>&1)"
CLI_STATUS=$?
set -e
case "$CLI_OUTPUT" in
  "omairc "*)
    echo "CLI treated message text as --version." >&2
    exit 1
    ;;
esac
if [ "$CLI_STATUS" -eq 0 ]; then
  echo "CLI send invocation unexpectedly succeeded without a server." >&2
  exit 1
fi

mkdir -p "$ROOT/build-tests"
cd "$ROOT/build-tests"
"$QMAKE" "$ROOT/tests/tests.pro"
make -j"$JOBS"
if [ "$(uname -s)" = Darwin ]; then
  # SecureTransport otherwise imports the loopback TLS key into the login keychain.
  export QT_SSL_USE_TEMPORARY_KEYCHAIN=1
fi
./protocol_tests

mkdir -p "$ROOT/build-seeded-qml-tests"
cd "$ROOT/build-seeded-qml-tests"
"$QMAKE" "$ROOT/tests/ui/seeded-qml.pro"
make -j"$JOBS"

mkdir -p "$ROOT/test-artifacts"
SCREENSHOTS="switch-channel send-message toggle-members open-direct-message"
for screenshot in $SCREENSHOTS; do
  rm -f -- "$ROOT/test-artifacts/$screenshot.png"
done

cd "$ROOT"
XDG_CONFIG_HOME="$TEST_STATE/config" \
XDG_CACHE_HOME="$TEST_STATE/cache" \
XDG_DATA_HOME="$TEST_STATE/data" \
XDG_STATE_HOME="$TEST_STATE/state" \
QT_QPA_PLATFORM=offscreen \
QT_QPA_PLATFORMTHEME= \
QT_QUICK_BACKEND=software \
"$ROOT/build-seeded-qml-tests/seeded_qml_tests" -input "$ROOT/tests/ui/tst_omairc.qml"

cd "$ROOT"
XDG_CONFIG_HOME="$TEST_STATE/config" \
XDG_CACHE_HOME="$TEST_STATE/cache" \
XDG_DATA_HOME="$TEST_STATE/data" \
XDG_STATE_HOME="$TEST_STATE/state" \
QT_QPA_PLATFORM=offscreen \
QT_QPA_PLATFORMTHEME= \
QT_QUICK_BACKEND=software \
"$ROOT/build-seeded-qml-tests/seeded_qml_tests" -input "$ROOT/tests/ui/tst_seeded_window.qml"

cd "$ROOT"
XDG_CONFIG_HOME="$TEST_STATE/config" \
XDG_CACHE_HOME="$TEST_STATE/cache" \
XDG_DATA_HOME="$TEST_STATE/data" \
XDG_STATE_HOME="$TEST_STATE/state" \
QT_QPA_PLATFORM=offscreen \
QT_QPA_PLATFORMTHEME= \
QT_QUICK_BACKEND=software \
"$ROOT/build-seeded-qml-tests/seeded_qml_tests" -input "$ROOT/tests/ui/tst_seeded_profiles.qml"

mkdir -p "$ROOT/build-live-ui-tests"
cd "$ROOT/build-live-ui-tests"
"$QMAKE" "$ROOT/tests/live-ui/live-ui.pro"
make -j"$JOBS"

mkdir -p "$ROOT/test-artifacts/live-ui"
rm -f -- "$ROOT/test-artifacts/live-ui/live-ui-grouped-messages.png"
rm -f -- "$ROOT/test-artifacts/live-ui/live-ui-replay-history.png"
rm -f -- "$ROOT/test-artifacts/live-ui/live-ui-bouncer-direct.png"
rm -f -- "$ROOT/test-artifacts/live-ui/live-ui-find.png"
rm -f -- "$ROOT/test-artifacts/live-ui/live-ui-seeded-demo-world.png"
for screenshot in $SCREENSHOTS; do
  rm -f -- "$ROOT/test-artifacts/$screenshot.png"
done

cd "$ROOT"
XDG_CONFIG_HOME="$TEST_STATE/config" \
XDG_CACHE_HOME="$TEST_STATE/cache" \
XDG_DATA_HOME="$TEST_STATE/data" \
QT_QPA_PLATFORM=offscreen \
QT_QPA_PLATFORMTHEME= \
QT_QUICK_BACKEND=software \
OMAIRC_LIVE_UI_ARTIFACTS="$ROOT/test-artifacts/live-ui" \
OMAIRC_UI_ARTIFACTS="$ROOT/test-artifacts" \
"$ROOT/build-live-ui-tests/live_ui_tests" consecutiveSameAuthorMinuteGroupsThroughIrcEvent memberJoinPartModeUpdatesWithoutReset replayAndLiveSameAuthorMinuteDoNotGroupThroughIrcEvent bouncerQueryReplayRendersDirectMessageInSidebar ctrlFFindsLiveTranscriptAndStatus seededIrcFixtureFurnishesDemoWorld selfAwayShowsOnEveryChannelRow directMessagePresenceFollowsAwayAndOffline

if [ ! -s "$ROOT/test-artifacts/live-ui/live-ui-grouped-messages.png" ]; then
  echo "live_ui_tests did not create test-artifacts/live-ui/live-ui-grouped-messages.png." >&2
  exit 1
fi
if [ ! -s "$ROOT/test-artifacts/live-ui/live-ui-replay-history.png" ]; then
  echo "live_ui_tests did not create test-artifacts/live-ui/live-ui-replay-history.png." >&2
  exit 1
fi
if [ ! -s "$ROOT/test-artifacts/live-ui/live-ui-bouncer-direct.png" ]; then
  echo "live_ui_tests did not create test-artifacts/live-ui/live-ui-bouncer-direct.png." >&2
  exit 1
fi
if [ ! -s "$ROOT/test-artifacts/live-ui/live-ui-find.png" ]; then
  echo "live_ui_tests did not create test-artifacts/live-ui/live-ui-find.png." >&2
  exit 1
fi
if [ ! -s "$ROOT/test-artifacts/live-ui/live-ui-seeded-demo-world.png" ]; then
  echo "live_ui_tests did not create test-artifacts/live-ui/live-ui-seeded-demo-world.png." >&2
  exit 1
fi
for screenshot in $SCREENSHOTS; do
  if [ ! -s "$ROOT/test-artifacts/$screenshot.png" ]; then
    echo "live_ui_tests did not create test-artifacts/$screenshot.png." >&2
    exit 1
  fi
done
