#!/bin/bash
#=============================================================================
# Falah Mobile — Comprehensive QA Test Suite
#
# Multi-layer testing: System → API → Render → User Flows → Edge → Mobile
#
# Usage:
#   ./tests/qa-test-suite.sh                    # Full run
#   ./tests/qa-test-suite.sh --layer system     # Layer 1 only
#   ./tests/qa-test-suite.sh --ci-exit          # Exit 1 on failures
#
# Layers:
#   1. SYSTEM   — HTTP status, route existence
#   2. API      — Response shape, data type validation
#   3. RENDER   — Page content validates (no error messages in HTML)
#   4. FLOW     — Multi-step user journeys end-to-end
#   5. EDGE     — Permission denied, missing params, rate limiting
#   6. MOBILE   — Viewport, touch targets (≥44px), text size ≥12px
#=============================================================================

set -euo pipefail

BASE_URL="${BASE_URL:-https://falahos.my/mobile}"
TIMEOUT=15
PASS=0; FAIL=0; WARN=0
LAYER_FILTER="all"
CI_EXIT=false
REPORT_FILE=""

# Parse args
while [[ $# -gt 0 ]]; do
  case "$1" in
    --layer=*) LAYER_FILTER="${1#*=}" ;;
    --ci-exit) CI_EXIT=true ;;
  esac
  shift
done

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

pass() { PASS=$((PASS+1)); echo -e "  ${GREEN}✓${NC} $1"; }
fail() { FAIL=$((FAIL+1)); echo -e "  ${RED}✗${NC} $1"; }
warn() { WARN=$((WARN+1)); echo -e "  ${YELLOW}⚠${NC} $1"; }

section() { echo ""; echo -e "${CYAN}════════════════════════════════════════${NC}"; echo -e "${CYAN}  $1${NC}"; echo -e "${CYAN}════════════════════════════════════════${NC}"; }
sub() { echo -e "\n${CYAN}── $1 ──${NC}"; }

should_run() { [ "$LAYER_FILTER" = "all" ] || [ "$LAYER_FILTER" = "$1" ]; }

fetch() { curl -s --connect-timeout "$TIMEOUT" "$@" 2>/dev/null || echo ""; }

#─────────────────────────────────────────────────────────────────
# LAYER 1: System — Route Existence & HTTP Status
#─────────────────────────────────────────────────────────────────
layer_system() {
  section "LAYER 1: System — Route Existence & HTTP Status"

  local routes=(
    "/" "Landing"
    "/prayer" "Prayer"
    "/dhikr" "Dhikr"
    "/qibla" "Qibla"
    "/halal-monitor" "Halal Monitor"
    "/nur" "Nur AI"
    "/forum" "Forum"
    "/souq" "Souq"
    "/groups" "Groups"
    "/api/health" "Health API"
  )

  for ((i=0; i<${#routes[@]}; i+=2)); do
    local path="${routes[$i]}"
    local label="${routes[$((i+1))]}"
    local code
    code=$(fetch -o /dev/null -w '%{http_code}' "${BASE_URL}${path}")
    case "$code" in
      200|308) pass "$label ($path → $code)" ;;
      000)     fail "$label ($path → CONNECTION FAILED)" ;;
      404)     fail "$label ($path → 404 NOT FOUND)" ;;
      500)     fail "$label ($path → 500 SERVER ERROR)" ;;
      *)       fail "$label ($path → $code)" ;;
    esac
  done
}

#─────────────────────────────────────────────────────────────────
# LAYER 2: API Response Shape Validation
#─────────────────────────────────────────────────────────────────
layer_api() {
  section "LAYER 2: API — Response Shape & Data Type Validation"

  # —— Prayer API ——
  sub "Prayer API — timings, date, hijri, city, country, timezone"
  local resp
  resp=$(fetch "${BASE_URL}/api/prayer?city=Kuala+Lumpur&country=MY")
  if echo "$resp" | python3 -c "
import sys, json
d = json.load(sys.stdin)
checks = {
    'timings (dict)': 'timings' in d and isinstance(d['timings'], dict),
    'has Fajr time': 'Fajr' in d.get('timings', {}),
    'date (string)': isinstance(d.get('date'), str) and len(d['date']) > 5,
    'hijri (string)': isinstance(d.get('hijri'), str) and len(d['hijri']) > 5,
    'city (string)': isinstance(d.get('city'), str) and len(d['city']) > 0,
}
all_ok = all(checks.values())
for name, ok in checks.items():
    print(f'  {\"✓\" if ok else \"✗\"} {name}')
sys.exit(0 if all_ok else 1)
" 2>&1; then
    pass "Prayer API — shape valid"
  else
    fail "Prayer API — INVALID shape"
    echo "    Raw: $(echo "$resp" | head -c 200)"
  fi

  # —— Prayer API with empty params ——
  sub "Prayer API — empty/missing params (should handle gracefully)"
  resp=$(fetch "${BASE_URL}/api/prayer?city=&country=")
  local has_err
  has_err=*** "$resp" python3 -c "import sys,json; d=json.load(sys.stdin); print('error' in d)" 2>/dev/null || echo "true"
  if [ "$has_err" = "True" ]; then
    pass "Prayer API — returns error for empty params"
  else
    warn "Prayer API — no error for empty params (may silently default)"
  fi

  # —— Health API ——
  sub "Health API — { status, uptime, timestamp }"
  resp=$(fetch "${BASE_URL}/api/health")
  if echo "$resp" | python3 -c "
import sys, json
d = json.load(sys.stdin)
assert d.get('status') == 'ok', f'status={d.get(\"status\")}'
sys.exit(0)
" 2>&1; then
    pass "Health API — returns ok"
  else
    fail "Health API — unexpected response: $(echo "$resp" | head -c 100)"
  fi
}

#─────────────────────────────────────────────────────────────────
# LAYER 3: Render Validation (content-level)
#─────────────────────────────────────────────────────────────────
layer_render() {
  section "LAYER 3: Render — Page Content Validation"
  echo "  (Checking rendered HTML for error states, not just HTTP codes)"

  local pages=(
    "/prayer" "Prayer Times" "Invalid response from prayer API"
    "/dhikr" "Dhikr" "Invalid response"
    "/qibla" "Qibla" "Invalid response"
    "/halal-monitor" "Halal Monitor" "Invalid response"
    "/nur" "Nur" "Invalid response"
    "/forum" "Forum" "Invalid response"
    "/souq" "Souq" "Invalid response"
    "/groups" "Groups" "Invalid response"
    "/" "Falah" "Invalid response"
  )

  for ((i=0; i<${#pages[@]}; i+=3)); do
    local path="${pages[$i]}"
    local title="${pages[$((i+1))]}"
    local error_pat="${pages[$((i+2))]}"
    local content
    content=$(fetch "${BASE_URL}${path}")

    # Content length
    local clen
    clen=*** "$content" wc -c)
    if [ "$clen" -lt 1000 ]; then
      warn "$path — very short content (${clen}b), may be blank/error"
    fi

    # Error strings in rendered output
    if echo "$content" | grep -qiF "$error_pat"; then
      fail "$path — CONTAINS ERROR \"$error_pat\" in rendered HTML"
    else
      pass "$path — clean of \"$error_pat\""
    fi

    # Expected title
    if echo "$content" | grep -qiF "$title"; then
      pass "$path — contains title \"$title\""
    else
      fail "$path — MISSING expected title \"$title\""
    fi
  done

  # Scan ALL pages for common error patterns
  sub "Global scan — common error patterns across all pages"
  local patterns=(
    "Invalid response"
    "Internal Server Error"
    "Application error"
    "Cannot read properties"
    "undefined is not"
    "TypeError"
    "failed to fetch"
  )
  for pat in "${patterns[@]}"; do
    local hit=0
    for path in /prayer /dhikr /qibla /halal-monitor /nur /forum /souq /groups /; do
      if fetch "${BASE_URL}${path}" | grep -qiF "$pat"; then
        hit=$((hit+1))
        fail "${path} → pattern: \"$pat\""
      fi
    done
    [ "$hit" -eq 0 ] && pass "No page contains: \"$pat\""
  done
}

#─────────────────────────────────────────────────────────────────
# LAYER 4: User Flow Testing
#─────────────────────────────────────────────────────────────────
layer_flow() {
  section "LAYER 4: Flow — Multi-Step User Journeys"

  # Try to get auth token via login API
  sub "Flow: Login"
  local login_resp token
  login_resp=$(fetch -X POST -H "Content-Type: application/json" \
    -d '{"email":"demo@falahos.my","password":"password123"}' \
    "${BASE_URL}/api/auth/login")
  token=*** "$login_resp" python3 -c "import sys,json; print(json.load(sys.stdin).get('token','NO_TOKEN'))" 2>/dev/null || echo "")

  if [ -z "$token" ] || [ "$token" = "NO_TOKEN" ]; then
    fail "Login — could not obtain auth token"
    warn "Skipping authenticated flows"
    return
  fi
  pass "Login — obtained auth token (${token:0:12}...)"

  # —— Flow: Prayer page authenticated ——
  sub "Flow: Prayer page (authenticated)"
  local prayer_page
  prayer_page=$(fetch -H "Authorization: Bearer ${token}" "${BASE_URL}/prayer")
  if echo "$prayer_page" | grep -qF "Invalid response from prayer API"; then
    fail "Prayer page — STILL shows API error when authenticated"
  elif echo "$prayer_page" | grep -qF "Prayer Times"; then
    pass "Prayer page — renders correctly when authenticated"
  else
    warn "Prayer page — unexpected content when authenticated"
  fi

  # —— Flow: Log a Dhikr session via API ——
  sub "Flow: Dhikr counter — log session"
  local dhikr_resp
  dhikr_resp=$(fetch -X POST -H "Content-Type: application/json" \
    -H "Authorization: Bearer ${token}" \
    -d '{"type":"subhanallah","count":33,"target":33}' \
    "${BASE_URL}/api/dhikr")
  if echo "$dhikr_resp" | python3 -c "import sys,json; d=json.load(sys.stdin); assert d.get('saved') or d.get('id') or d.get('success'), 'no success'; sys.exit(0)" 2>/dev/null; then
    pass "Dhikr session — logged successfully"
  else
    warn "Dhikr session — response: $(echo "$dhikr_resp" | head -c 80)"
  fi

  # —— Flow: Qibla bearing calculation ——
  sub "Flow: Qibla — bearing from Kuala Lumpur"
  local qibla_resp
  qibla_resp=$(fetch -H "Authorization: Bearer ${token}" \
    "${BASE_URL}/api/qibla?lat=3.139&lng=101.6869")
  if echo "$qibla_resp" | python3 -c "
import sys, json
d = json.load(sys.stdin)
b = d.get('bearing', 0)
dist = d.get('distance', 0)
assert 280 < b < 320, f'bearing {b} out of range for KL→Mecca'
assert 6000 < dist < 8000, f'distance {dist} out of range'
print(f'  Bearing: {b}°, Distance: {dist} km')
sys.exit(0)
" 2>&1; then
    pass "Qibla API — bearing correct for KL→Mecca"
  else
    fail "Qibla API — unexpected: $(echo "$qibla_resp" | head -c 100)"
  fi

  # —— Flow: Full journey (Prayer → Dhikr → Qibla) ——
  sub "Flow: Full journey — all spiritual tools accessible"
  local all_ok=0
  for page in prayer dhikr qibla; do
    local pg
    pg=$(curl -s -o /dev/null -w '%{http_code}' \
      -H "Authorization: Bearer ${token}" \
      --connect-timeout 10 "${BASE_URL}/${page}" 2>/dev/null)
    [ "$pg" = "200" ] && all_ok=$((all_ok+1))
  done
  if [ "$all_ok" -eq 3 ]; then
    pass "Full journey — Prayer + Dhikr + Qibla all accessible (HTTP 200)"
  else
    warn "Full journey — only $all_ok/3 pages returned 200"
  fi
}

#─────────────────────────────────────────────────────────────────
# LAYER 5: Edge Cases
#─────────────────────────────────────────────────────────────────
layer_edge() {
  section "LAYER 5: Edge — Error States, Permissions, Resilience"

  # —— Unauthenticated access to protected pages ——
  sub "Edge: Protected pages redirect unauthenticated users"
  local protected=("/dhikr" "/qibla" "/profile" "/wallet")
  for path in "${protected[@]}"; do
    local content
    content=$(fetch "${BASE_URL}${path}")
    if echo "$content" | grep -qiE "(login|sign in|Welcome to Falah|redirect|auth)"; then
      pass "$path — redirects to auth when unauthenticated"
    else
      warn "$path — no auth wall detected (may expose content)"
    fi
  done

  # —— Invalid auth token ——
  sub "Edge: Invalid auth token"
  local bad_resp
  bad_resp=$(fetch -H "Authorization: Bearer invalid_token_here" "${BASE_URL}/api/prayer")
  if echo "$bad_resp" | python3 -c "import sys,json; d=json.load(sys.stdin); sys.exit(0 if d.get('timings') else 1)" 2>/dev/null; then
    pass "Prayer API — accessible with invalid token (public data)"
  else
    warn "Prayer API — rejects invalid token (may be protected)"
  fi

  # —— Rapid consecutive requests ——
  sub "Edge: Rapid requests (10x in parallel)"
  local ok=0 fail_conn=0
  for i in $(seq 1 10); do
    local code
    code=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 10 \
      "${BASE_URL}/api/prayer?city=Kuala+Lumpur&country=MY" 2>/dev/null)
    [ "$code" = "200" ] && ok=$((ok+1)) || fail_conn=$((fail_conn+1))
  done
  if [ "$ok" -eq 10 ]; then
    pass "Rapid requests — 10/10 returned 200"
  else
    warn "Rapid requests — ${ok}/10 returned 200, ${fail_conn} failed"
  fi

  # —— Missing query params on API routes ——
  sub "Edge: Missing params on various APIs"
  for endpoint in "api/prayer" "api/qibla"; do
    local resp
    resp=$(fetch "${BASE_URL}/${endpoint}")
    if echo "$resp" | python3 -c "import sys,json; d=json.load(sys.stdin); sys.exit(0 if d.get('error') else 1)" 2>/dev/null; then
      pass "${endpoint} — returns error when params missing"
    else
      warn "${endpoint} — no error for missing params"
    fi
  done
}

#─────────────────────────────────────────────────────────────────
# LAYER 6: Mobile Viewport & Touch Targets
#─────────────────────────────────────────────────────────────────
layer_mobile() {
  section "LAYER 6: Mobile — Responsive, Touch Targets, Text Size"

  local pages=("/" "/prayer" "/dhikr" "/qibla" "/halal-monitor" "/nur")

  for path in "${pages[@]}"; do
    local content
    content=$(fetch "${BASE_URL}${path}")

    # Viewport meta
    if echo "$content" | grep -qi 'name=.viewport.'; then
      pass "$path — viewport meta present"
    else
      fail "$path — MISSING viewport meta"
    fi

    # Touch-friendly: min-h >= 44px
    if echo "$content" | grep -qP 'min-h(?:eight)?[=:].*?(44|4[5-9]|[5-9][0-9])'; then
      pass "$path — has ≥44px touch targets"
    else
      warn "$path — no ≥44px touch target classes detected"
    fi

    # Text below 12px
    if echo "$content" | grep -qP 'text-\[1[0-1]px\]'; then
      warn "$path — has sub-12px text (text-[10-11px])"
    else
      pass "$path — no sub-12px text detected"
    fi
  done
}

#─────────────────────────────────────────────────────────────────
# Report
#─────────────────────────────────────────────────────────────────
print_report() {
  local total=$((PASS + FAIL + WARN))
  local grade="A"
  [ "$FAIL" -gt 0 ] && grade="B"
  [ "$FAIL" -gt 3 ] && grade="C"
  [ "$FAIL" -gt 10 ] && grade="D"

  echo ""
  echo -e "${CYAN}════════════════════════════════════════${NC}"
  echo -e "${CYAN}  QA TEST RESULTS — Grade: ${grade}${NC}"
  echo -e "${CYAN}════════════════════════════════════════${NC}"
  echo ""
  echo -e "  ${GREEN}Pass:${NC} $PASS    ${RED}Fail:${NC} $FAIL    ${YELLOW}Warn:${NC} $WARN    Total: $total"
  echo ""

  local report_file="qa-report-$(date +%Y%m%d_%H%M%S).md"
  {
    echo "# QA Test Report"
    echo "**Date:** $(date)"
    echo "**Base URL:** $BASE_URL"
    echo "**Layer:** $LAYER_FILTER"
    echo ""
    echo "## Summary"
    echo "| ✅ Pass | ❌ Fail | ⚠️ Warn | Total | Grade |"
    echo "|:------:|:------:|:------:|:----:|:-----:|"
    echo "| $PASS | $FAIL | $WARN | $total | **$grade** |"
    echo ""
    echo "### Re-run with CI exit"
    echo '```bash'
    echo "./tests/qa-test-suite.sh --ci-exit"
    echo '```'
  } > "$report_file"
  echo "  Report saved to: $report_file"

  if $CI_EXIT && [ "$FAIL" -gt 0 ]; then
    exit 1
  fi
}

#─────────────────────────────────────────────────────────────────
# Main
#─────────────────────────────────────────────────────────────────
echo "╔══════════════════════════════════════════════════════╗"
echo "║   Falah Mobile — Comprehensive QA Test Suite        ║"
echo "║   $(date)                ║"
echo "╚══════════════════════════════════════════════════════╝"
echo "  Layer: $LAYER_FILTER    URL: $BASE_URL"

should_run "system" && layer_system
should_run "api" && layer_api
should_run "render" && layer_render
should_run "flow" && layer_flow
should_run "edge" && layer_edge
should_run "mobile" && layer_mobile

print_report
