#!/bin/bash
# ============================================================================
# ODS ods-preflight.sh Test Suite
# ============================================================================
# Validates that ods-preflight.sh is syntactically correct, follows the
# project's shell style requirements, and encodes the correct LLM port
# default (8080, not 11434).
#
# These tests are static (no running Docker) — they inspect the script itself.
# Integration-level tests (actual service probing) are covered in
# tests/test-health-check.sh and tests/test-integration.sh.
#
# Usage: bash tests/test-preflight.sh
# Exit codes: 0 = all pass, 1 = one or more failures
# ============================================================================

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
PREFLIGHT="$ROOT_DIR/ods-preflight.sh"

GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'

PASSED=0
FAILED=0

pass() { printf "  ${GREEN}✓ PASS${NC} %s\n" "$1"; PASSED=$((PASSED + 1)); }
fail() { printf "  ${RED}✗ FAIL${NC} %s\n" "$1"; FAILED=$((FAILED + 1)); }
skip() { printf "  ${YELLOW}⊘ SKIP${NC} %s\n" "$1"; }

echo ""
echo "╔════════════════════════════════════════════════╗"
echo "║   ods-preflight.sh Test Suite               ║"
echo "╚════════════════════════════════════════════════╝"
echo ""

# ── Static checks ──────────────────────────────────────────────────────────

# 1. Script exists
if [[ ! -f "$PREFLIGHT" ]]; then
    fail "ods-preflight.sh not found at $PREFLIGHT"
    echo ""
    echo "Result: $PASSED passed, $FAILED failed"
    exit 1
fi
pass "ods-preflight.sh exists"

# 2. Script passes bash syntax check
if bash -n "$PREFLIGHT" 2>/dev/null; then
    pass "bash -n syntax check passes"
else
    fail "bash -n syntax check failed"
fi

# 3. Uses set -euo pipefail (project style requirement per CONTRIBUTING.md)
if grep -q 'set -euo pipefail' "$PREFLIGHT"; then
    pass "set -euo pipefail present"
else
    fail "set -euo pipefail missing — CONTRIBUTING.md requires this in all bash files"
fi

# 4. LLM port default is 8080, NOT 11434
# config/ports.json and docker-compose.base.yml define the canonical default as 8080.
# 11434 is only the Strix Halo AMD override (written to .env by phase 06).
# The fallback in the script must be 8080 so plain installs without OLLAMA_PORT in
# .env get the correct port probed.
if grep -q 'LLAMA_SERVER_PORT:-8080' "$PREFLIGHT"; then
    pass "LLM port fallback is 8080 (aligns with config/ports.json)"
else
    fail "LLM port fallback is not 8080 — check the OLLAMA_PORT expansion in ods-preflight.sh"
fi

# 5. Does NOT contain the old wrong fallback of 11434 in port resolution
if grep -q 'LLAMA_SERVER_PORT:-11434' "$PREFLIGHT"; then
    fail "Old wrong LLM port fallback 11434 still present — should be 8080"
else
    pass "Old wrong LLM port fallback 11434 is gone"
fi

# 6. detect_backend function is present
if grep -q 'detect_backend()' "$PREFLIGHT"; then
    pass "detect_backend function present"
else
    fail "detect_backend function missing"
fi

# 7. AMD sysfs scan iterates all DRM cards (not just card1)
if grep -q '/sys/class/drm/card\*/device' "$PREFLIGHT"; then
    pass "AMD sysfs scan uses glob (all DRM cards)"
else
    fail "AMD sysfs scan missing wildcard — may miss some AMD GPUs"
fi

# 8. Script uses BASH_SOURCE for portability (not $0)
if grep -q 'BASH_SOURCE' "$PREFLIGHT"; then
    pass "Uses BASH_SOURCE for script dir resolution"
else
    fail "Missing BASH_SOURCE — \$0 breaks when script is sourced"
fi

# 9. Summary section has all expected check sections
for check_label in "Checking Docker" "Checking Docker Compose" "Checking GPU" \
                   "Checking LLM endpoint" "Checking Whisper" "Checking TTS" \
                   "Checking Embeddings" "Checking Dashboard"; do
    if grep -q "$check_label" "$PREFLIGHT"; then
        pass "Check section present: $check_label"
    else
        fail "Check section missing: $check_label"
    fi
done

# 10. Uses docker port to probe actual external port mapping (not just hardcoded)
if grep -q 'docker port ods-llama-server' "$PREFLIGHT"; then
    pass "Probes actual Docker port mapping via 'docker port'"
else
    fail "Does not probe actual Docker port mapping"
fi

# 11. External Lemonade mode checks LiteLLM, not a managed llama-server container
if grep -q 'is_external_lemonade()' "$PREFLIGHT" \
   && grep -q 'LiteLLM external Lemonade gateway' "$PREFLIGHT" \
   && grep -q 'ods-litellm' "$PREFLIGHT"; then
    pass "External Lemonade preflight checks LiteLLM gateway"
else
    fail "External Lemonade preflight must not require managed ods-llama-server"
fi

# 12. Extension health checks honor .env port overrides
# Linux AMD/Lemonade reserves host port 9000 for Lemonade, so the installer may
# write WHISPER_PORT=9100. Root preflight must follow that configured port
# instead of probing a stale hard-coded default.
if grep -q 'WHISPER_PORT_RESOLVED="${WHISPER_PORT:-9000}"' "$PREFLIGHT" \
   && grep -q 'TTS_PORT_RESOLVED="${TTS_PORT:-8880}"' "$PREFLIGHT" \
   && grep -q 'EMBEDDINGS_PORT_RESOLVED="${EMBEDDINGS_PORT:-8090}"' "$PREFLIGHT"; then
    pass "Extension health checks honor configured port overrides"
else
    fail "Extension health checks must honor WHISPER_PORT/TTS_PORT/EMBEDDINGS_PORT"
fi

if grep -q 'WHISPER_ENDPOINTS=("http://${SERVICE_HOST}:9000"' "$PREFLIGHT"; then
    fail "Whisper preflight still hard-codes host port 9000"
else
    pass "Whisper preflight no longer hard-codes host port 9000"
fi

# ── Runtime smoke test (no Docker required) ─────────────────────────────────

# 13. Script runs to completion without unbound variable or syntax errors
#     (Services won't be up, so we expect exit 1 — that is correct behavior)
set +e
err_output=$(
    SERVICE_HOST=localhost \
    OLLAMA_PORT="" \
    LLAMA_SERVER_PORT="" \
    GPU_BACKEND="" \
    bash "$PREFLIGHT" 2>&1
)
run_exit=$?
set -e

if echo "$err_output" | grep -qiE 'unbound variable|syntax error|command not found: \['; then
    fail "Script produced shell error: $(echo "$err_output" | grep -iE 'unbound variable|syntax error' | head -1)"
else
    pass "Script runs without shell errors (exit $run_exit is expected)"
fi

# 14. Exit code is 0 or 1; never an unexpected crash code
if [[ "$run_exit" -eq 0 ]] || [[ "$run_exit" -eq 1 ]]; then
    pass "Exit code is valid (0=pass, 1=fail): $run_exit"
else
    fail "Unexpected exit code $run_exit — script may have crashed"
fi

# ── Summary ────────────────────────────────────────────────────────────────

echo ""
echo "Result: $PASSED passed, $FAILED failed"
echo ""
[[ $FAILED -eq 0 ]]
