#!/usr/bin/env zsh

emulate -L zsh
setopt no_unset pipe_fail

integer failures=0
tmpdir=""

log_ok() {
  print -r -- "PASS: $1"
}

log_fail() {
  print -u2 -r -- "FAIL: $1"
  failures+=1
}

find_tool() {
  local preferred="$1"
  shift

  if [[ -n "$preferred" ]] && command -v -- "$preferred" >/dev/null 2>&1; then
    print -r -- "$preferred"
    return 0
  fi

  local candidate
  for candidate in "$@"; do
    if command -v -- "$candidate" >/dev/null 2>&1; then
      print -r -- "$candidate"
      return 0
    fi
  done

  return 1
}

cleanup() {
  if [[ -n "$tmpdir" && -d "$tmpdir" ]]; then
    rm -rf -- "$tmpdir"
  fi
}

trap cleanup EXIT INT TERM HUP

print -r -- 'Linux by Intent host readiness check (zsh)'

if command -v sh >/dev/null 2>&1 && sh -c 'exit 0' >/dev/null 2>&1; then
  log_ok 'sh is available and executable'
else
  log_fail 'sh is missing or cannot execute commands'
fi

for tool in git gzip awk cmake meson rustc cargo rsync clang ninja bmake; do
  if command -v -- "$tool" >/dev/null 2>&1; then
    log_ok "$tool is installed"
  else
    log_fail "$tool is missing"
  fi
done

yacc_cmd=$(find_tool "${YACC-}" yacc byacc || true)
if [[ -n "$yacc_cmd" ]]; then
  log_ok "yacc-compatible parser generator found: $yacc_cmd"
else
  log_fail 'no yacc-compatible parser generator was found'
fi

cc_cmd=$(find_tool "${CC-}" cc clang gcc || true)
cxx_cmd=$(find_tool "${CXX-}" c++ clang++ g++ || true)

if [[ -n "$cc_cmd" ]]; then
  log_ok "C compiler found: $cc_cmd"
else
  log_fail 'no working C compiler command was found'
fi

if [[ -n "$cxx_cmd" ]]; then
  log_ok "C++ compiler found: $cxx_cmd"
else
  log_fail 'no working C++ compiler command was found'
fi

if [[ -n "$cc_cmd" && -n "$cxx_cmd" ]]; then
  tmpdir=$(mktemp -d 2>/dev/null || mktemp -d -t linuxbook-ready)

  cat > "$tmpdir/test.c" <<'EOF'
#include <stdio.h>

int main(void) {
  puts("c-ok");
  return 0;
}
EOF

  if "$cc_cmd" -o "$tmpdir/test-c" "$tmpdir/test.c" >/dev/null 2>&1 && "$tmpdir/test-c" >/dev/null 2>&1; then
    log_ok 'C compilation and execution succeeded'
  else
    log_fail 'C compilation or execution failed'
  fi

  cat > "$tmpdir/test.cpp" <<'EOF'
#include <iostream>

int main() {
  std::cout << "cpp-ok\n";
  return 0;
}
EOF

  if "$cxx_cmd" -o "$tmpdir/test-cpp" "$tmpdir/test.cpp" >/dev/null 2>&1 && "$tmpdir/test-cpp" >/dev/null 2>&1; then
    log_ok 'C++ compilation and execution succeeded'
  else
    log_fail 'C++ compilation or execution failed'
  fi

  cat > "$tmpdir/libcheck.c" <<'EOF'
int readiness_value(void) {
  return 42;
}
EOF

  cat > "$tmpdir/linkcheck.c" <<'EOF'
int readiness_value(void);

int main(void) {
  return readiness_value() == 42 ? 0 : 1;
}
EOF

  if "$cc_cmd" -c -o "$tmpdir/libcheck.o" "$tmpdir/libcheck.c" >/dev/null 2>&1 && \
    "$cc_cmd" -c -o "$tmpdir/linkcheck.o" "$tmpdir/linkcheck.c" >/dev/null 2>&1 && \
    "$cc_cmd" -o "$tmpdir/link-test" "$tmpdir/linkcheck.o" "$tmpdir/libcheck.o" >/dev/null 2>&1 && \
    "$tmpdir/link-test" >/dev/null 2>&1; then
    log_ok 'linking object files into an executable succeeded'
  else
    log_fail 'linking test failed'
  fi
fi

if (( failures == 0 )); then
  print -r -- 'RESULT: system appears ready for the book'
  exit 0
fi

print -u2 -r -- "RESULT: system is not ready for the book ($failures failure(s))"
exit 1
