#!/usr/bin/env bash
# adom-digikey smoke test — real-backend search assertions.
#
# Runs a fixed set of real-world keyword queries against the Node + SQLite
# backend and asserts each returns at least one component whose `mfr` field
# contains the expected substring. Catches regressions like the 2026-04 bug
# where handleSearch destructured `query` but every caller sent `keyword`,
# silently routing all searches to "top stocked parts" (capacitors).
#
# Usage:
#   tests/smoke.sh                                                    # hits deployed backend
#   tests/smoke.sh http://127.0.0.1:8777                              # local backend
#   DIGIKEY_API=http://127.0.0.1:8777 tests/smoke.sh                   # same via env
#
# Exit code: 0 iff all cases pass. Non-zero + red FAIL line otherwise.

set -u

BACKEND="${1:-${DIGIKEY_API:-https://digikey-gjuu8l5t69uh.adom.cloud}}"
BACKEND="${BACKEND%/}"

# ANSI only on a real terminal (adom-cli-design rule: no color escapes in
# captured stdout).
if [ -t 1 ]; then
  C_OK=$'\033[32m'; C_FAIL=$'\033[31m'; C_DIM=$'\033[2m'; C_BOLD=$'\033[1m'; C_RESET=$'\033[0m'
else
  C_OK=''; C_FAIL=''; C_DIM=''; C_BOLD=''; C_RESET=''
fi

pass=0; fail=0; failures=()

run_case() {
  local label="$1" keyword="$2" expect_substr="$3" expect_min="${4:-1}"
  local body resp count match
  body=$(jq -n --arg k "$keyword" '{action:"search", keyword:$k, limit:5}')
  resp=$(curl -sS --max-time 10 -X POST "$BACKEND/" \
    -H 'content-type: application/json' -d "$body" 2>/dev/null)
  if [ -z "$resp" ]; then
    fail=$((fail+1)); failures+=("$label — backend unreachable or empty response")
    printf '%sFAIL%s  %-36s  %s\n' "$C_FAIL" "$C_RESET" "$label" "(no response)"
    return
  fi
  count=$(printf '%s' "$resp" | jq '.count // 0' 2>/dev/null)
  if [ -z "$expect_substr" ]; then
    # Just assert >= expect_min results, no substring check.
    if [ "$count" -ge "$expect_min" ]; then
      pass=$((pass+1))
      printf '%sPASS%s  %-36s  count=%s\n' "$C_OK" "$C_RESET" "$label" "$count"
    else
      fail=$((fail+1)); failures+=("$label — count=$count expected >=$expect_min")
      printf '%sFAIL%s  %-36s  count=%s (expected >=%s)\n' "$C_FAIL" "$C_RESET" "$label" "$count" "$expect_min"
    fi
    return
  fi
  match=$(printf '%s' "$resp" | jq --arg s "$expect_substr" \
    '[.components[]? | (.mpn // .mfr // "") + " " + (.description // "") | ascii_downcase | contains($s | ascii_downcase)] | any' 2>/dev/null)
  if [ "$match" = "true" ] && [ "$count" -ge "$expect_min" ]; then
    pass=$((pass+1))
    printf '%sPASS%s  %-36s  count=%s  mfr contains %s\n' "$C_OK" "$C_RESET" "$label" "$count" "$expect_substr"
  else
    fail=$((fail+1)); failures+=("$label — count=$count, mfr-contains-'$expect_substr'=$match")
    printf '%sFAIL%s  %-36s  count=%s  mfr contains %s? %s\n' \
      "$C_FAIL" "$C_RESET" "$label" "$count" "$expect_substr" "${match:-null}"
  fi
}

run_negative() {
  local label="$1" keyword="$2"
  local body resp count
  body=$(jq -n --arg k "$keyword" '{action:"search", keyword:$k, limit:5}')
  resp=$(curl -sS --max-time 10 -X POST "$BACKEND/" \
    -H 'content-type: application/json' -d "$body" 2>/dev/null)
  count=$(printf '%s' "$resp" | jq '.count // 0' 2>/dev/null)
  if [ "$count" = "0" ]; then
    pass=$((pass+1))
    printf '%sPASS%s  %-36s  count=0 (expected)\n' "$C_OK" "$C_RESET" "$label"
  else
    fail=$((fail+1)); failures+=("$label — nonsense keyword returned $count results (should be 0)")
    printf '%sFAIL%s  %-36s  count=%s (expected 0)\n' "$C_FAIL" "$C_RESET" "$label" "$count"
  fi
}

echo "${C_BOLD}adom-digikey smoke test${C_RESET}  ${C_DIM}backend: $BACKEND${C_RESET}"
echo "${C_DIM}────────────────────────────────────────────────────────${C_RESET}"

# Canonical MPNs that should always match.
run_case "esp32 (generic)"         "ESP32"              "esp32"       1
run_case "esp32-s3 (variant)"      "ESP32-S3"           "esp32-s3"    1
run_case "stm32f103 (arm mcu)"     "STM32F103"          "stm32f103"   1
run_case "lm358 (op-amp)"          "LM358"              "lm358"       1
run_case "ne555 (timer)"           "NE555"              "ne555"       1
run_case "tl072 (audio op-amp)"    "TL072"              "tl072"       1
run_case "atmega328 (arduino mcu)" "ATmega328"          "atmega328"   1
run_case "ams1117 (ldo)"           "AMS1117"            "ams1117"     1
run_case "ch340 (usb-uart)"        "CH340"              "ch340"       1
run_case "w25q (spi flash)"        "W25Q"               "w25q"        1

# DigiKey-specific MPN (LM1117-3.3 LDO).
run_case "lm1117-3.3 (ldo)"        "LM1117-3.3"         "lm1117"      1

# Broad keyword — at least one match.
run_case "100nF 0603 (keyword)"    "100nF 0603"         ""            1

# Nonsense query should return 0, not default fallback.
run_negative "bogus keyword"       "XYZZZZ999NOTAPART"

echo "${C_DIM}────────────────────────────────────────────────────────${C_RESET}"
if [ "$fail" -eq 0 ]; then
  echo "${C_OK}${C_BOLD}OK${C_RESET}  ${pass} passed, 0 failed"
  exit 0
else
  echo "${C_FAIL}${C_BOLD}FAIL${C_RESET}  ${pass} passed, ${fail} failed"
  for f in "${failures[@]}"; do echo "      - $f"; done
  exit 1
fi