#!/usr/bin/env bash
# selfcheck.sh — prove deadman is sound on THIS machine, in one command.
#
#   ./selfcheck.sh
#
# Prints one PASS/FAIL line per step, then RESULT PASS or RESULT FAIL.
# Exit code: 0 only if every step passed, 1 if any step failed, 2 if the
# script itself could not get started.

set -u

cd "$(dirname "$0")" 2>/dev/null || {
    echo "FAIL  cannot enter the directory selfcheck.sh lives in"
    echo "RESULT FAIL"
    exit 2
}

PY="${PYTHON:-python3}"
STEPS=0
FAILED=0
SCRATCH="selfcheck_state.json"

report() {
    # report <label> <rc> <evidence>   -- rc 0 means the step passed
    STEPS=$((STEPS + 1))
    if [ "$2" -eq 0 ]; then
        printf 'PASS  %s\n' "$1"
    else
        printf 'FAIL  %s\n' "$1"
        FAILED=$((FAILED + 1))
    fi
    if [ -n "${3:-}" ]; then
        printf '      %s\n' "$3"
    fi
}

# 1 -- the interpreter must be able to read the config format
OUT="$("$PY" -c 'import tomllib' 2>&1)"; RC=$?
report "python interpreter has tomllib ($("$PY" -V 2>&1))" "$RC" "$OUT"

# 2 -- both files must at least compile
OUT="$("$PY" -m py_compile deadman.py test_deadman.py 2>&1)"; RC=$?
report "py_compile deadman.py test_deadman.py" "$RC" "$OUT"

# 3 -- the test suite (this is the step that carries the real weight)
OUT="$("$PY" test_deadman.py 2>&1)"; RC=$?
LAST="$(printf '%s\n' "$OUT" | tail -n 1)"
report "test suite" "$RC" "$LAST"
if [ "$RC" -ne 0 ]; then
    printf '%s\n' "$OUT" | grep '^FAILED' | sed 's/^/      /'
fi

# 4 -- the shipped demo must work with no n8n instance, no API key and no
#      alert channel, and must exit 1 (it is demonstrating two failures)
rm -f "$SCRATCH"
OUT="$("$PY" deadman.py --config config.example.toml --simulate demo_fixture.json \
        --now 2026-11-13T12:00:00Z --state "$SCRATCH" 2>&1)"; RC=$?
if [ "$RC" -eq 1 ]; then
    DEMO_RC=0
    EVIDENCE="exit 1 as documented; $(printf '%s\n' "$OUT" | grep -c 'ALERT') alert line(s) shown"
else
    DEMO_RC=1
    EVIDENCE="expected exit 1 from the demo fixture, got $RC: $(printf '%s\n' "$OUT" | tail -n 1)"
fi
report "demo: --simulate shows the failure classes with no instance" "$DEMO_RC" "$EVIDENCE"

# 5 -- re-running the same demo must NOT re-alert (idempotence, from the CLI)
OUT="$("$PY" deadman.py --config config.example.toml --simulate demo_fixture.json \
        --now 2026-11-13T12:05:00Z --state "$SCRATCH" 2>&1)"; RC=$?
if [ "$RC" -eq 1 ] && ! printf '%s\n' "$OUT" | grep -q 'ALERT'; then
    IDEM_RC=0
    EVIDENCE="second run sent nothing new and still exited 1"
else
    IDEM_RC=1
    EVIDENCE="second run should send no ALERT and exit 1; got exit $RC: $(printf '%s\n' "$OUT" | tail -n 1)"
fi
report "idempotence: the same silence is not re-alerted on the next poll" "$IDEM_RC" "$EVIDENCE"

# 6 -- a missing config must be a clear probe fault, not a crash
OUT="$("$PY" deadman.py --config definitely-not-here.toml 2>&1)"; RC=$?
if [ "$RC" -eq 2 ] && printf '%s\n' "$OUT" | grep -q 'config file not found'; then
    BADCFG_RC=0
    EVIDENCE="exit 2 with a message that names the problem"
else
    BADCFG_RC=1
    EVIDENCE="expected exit 2 and 'config file not found', got exit $RC: $OUT"
fi
report "bad config is exit 2 with a named reason" "$BADCFG_RC" "$EVIDENCE"

rm -f "$SCRATCH"

echo
if [ "$FAILED" -eq 0 ]; then
    echo "RESULT PASS ($STEPS/$STEPS steps)"
    exit 0
fi
echo "RESULT FAIL ($FAILED of $STEPS steps failed)"
exit 1
