#!/bin/bash
# Smoke test: orderBy support for sf_gql_aggregate
#
# Tests a105, a114, a115, a119 from the aggregates assignment.
# Exits 0 only if all 4 pass. Writes results to stdout and
# SMOKE-RESULTS-orderby.txt for the ralph loop reflection.
#
# Usage: cd packages/graphiti && bash scripts/smoke-orderby.sh
#
# Prerequisites:
#   - pnpm build (clean, dist/ up to date)
#   - ebikes org authenticated via sf CLI (only needed for live runs;
#     the tool validates the schema cache, not live data)

set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WORK_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$WORK_DIR"

RESULTS_FILE="$WORK_DIR/SMOKE-RESULTS-orderby.txt"
PASS_COUNT=0
FAIL_COUNT=0
DETAILS=""

call_tool() {
  local args="$1"
  printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1"}}}\n{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"sf_gql_aggregate","arguments":%s}}\n' "$args" \
    | FORCE_COLOR=0 NO_COLOR=1 node dist/mcp/stdio.js 2>/dev/null \
    | sed -n '2p'
}

extract_query() {
  python3 -c "
import sys, json
line = sys.stdin.read().strip()
data = json.loads(line)
content = data.get('result',{}).get('content',[{}])[0].get('text','')
is_error = data.get('result',{}).get('isError', False)
if is_error:
    print('ERROR: ' + content)
else:
    parsed = json.loads(content)
    print(parsed.get('query',''))
"
}

normalize() {
  # Strip whitespace differences for comparison
  python3 -c "
import sys, re
q = sys.stdin.read().strip()
# Collapse all whitespace to single spaces
q = re.sub(r'\s+', ' ', q)
print(q)
"
}

check_orderby() {
  local id="$1"
  local input="$2"
  local expected_query="$3"
  local description="$4"

  local raw_result
  raw_result=$(call_tool "$input")

  local query
  query=$(echo "$raw_result" | extract_query)

  local status="FAIL"
  local note=""

  if echo "$query" | grep -q "^ERROR:"; then
    note="Tool returned error: $query"
  else
    # Normalize both for comparison
    local actual_norm
    actual_norm=$(echo "$query" | normalize)
    local expected_norm
    expected_norm=$(echo "$expected_query" | normalize)

    if [ "$actual_norm" = "$expected_norm" ]; then
      status="PASS"
      note="Query matches expected output exactly"
    else
      # Check key structural elements even if not exact match
      local has_orderby=false
      local has_function=false
      local has_order=false

      if echo "$query" | grep -q "orderBy"; then
        has_orderby=true
      fi
      if echo "$query" | grep -q "function:"; then
        has_function=true
      fi
      if echo "$query" | grep -qi "order:.*\(ASC\|DESC\)"; then
        has_order=true
      fi

      if [ "$has_orderby" = true ] && [ "$has_function" = true ] && [ "$has_order" = true ]; then
        # Has the right shape but doesn't match exactly
        note="Has orderBy with function and order direction but differs from expected.
Expected: $expected_norm
Actual:   $actual_norm"
      elif [ "$has_orderby" = false ]; then
        note="Missing orderBy clause entirely. Query: $(echo "$query" | head -5)"
      else
        note="orderBy present but missing function or order direction.
Expected: $expected_norm
Actual:   $actual_norm"
      fi
    fi
  fi

  if [ "$status" = "PASS" ]; then
    PASS_COUNT=$((PASS_COUNT + 1))
  else
    FAIL_COUNT=$((FAIL_COUNT + 1))
  fi

  local entry="### $id — $description
**Status:** $status
**Input:** $input
**Note:** $note
**Query output:**
\`\`\`graphql
$query
\`\`\`
**Expected:**
\`\`\`graphql
$expected_query
\`\`\`
"
  DETAILS="${DETAILS}${entry}
"
  echo "$status: $id — $note"
}

echo "=== OrderBy Smoke Tests ==="
echo ""

# a105: count Leads, groupBy CreatedDate CALENDAR_YEAR, orderBy Description count DESC
check_orderby \
  "a105_leads_by_created_year_ordered" \
  '{"org":"ebikes","object":"Lead","aggregations":[{"function":"count"}],"groupBy":[{"field":"CreatedDate","function":"CALENDAR_YEAR"}],"orderBy":{"Description":{"function":"COUNT","order":"DESC"}},"operationName":"LeadsByCreatedYearOrdered"}' \
  'query LeadsByCreatedYearOrdered($after: String) { uiapi { aggregate { Lead(groupBy: { CreatedDate: { function: CALENDAR_YEAR } }, orderBy: { Description: { function: COUNT, order: DESC } }, after: $after) { edges { node { aggregate { CreatedDate { value } countId: Id { count { value } } } } } pageInfo { hasNextPage endCursor } } } } }' \
  "count Leads groupBy CreatedDate CALENDAR_YEAR, orderBy Description count DESC"

# a114: count Opportunities, groupBy AccountId, orderBy Description count DESC
check_orderby \
  "a114_opps_by_account_ordered_by_count" \
  '{"org":"ebikes","object":"Opportunity","aggregations":[{"function":"count"}],"groupBy":["AccountId"],"orderBy":{"Description":{"function":"COUNT","order":"DESC"}},"operationName":"OppsByAccountOrdered"}' \
  'query OppsByAccountOrdered($after: String) { uiapi { aggregate { Opportunity(groupBy: { AccountId: { group: true } }, orderBy: { Description: { function: COUNT, order: DESC } }, after: $after) { edges { node { aggregate { AccountId { value } countId: Id { count { value } } } } } pageInfo { hasNextPage endCursor } } } } }' \
  "count Opportunities groupBy AccountId, orderBy Description count DESC"

# a115: count Cases, groupBy Priority, orderBy Description count ASC
check_orderby \
  "a115_cases_by_priority_ordered_by_count" \
  '{"org":"ebikes","object":"Case","aggregations":[{"function":"count"}],"groupBy":["Priority"],"orderBy":{"Description":{"function":"COUNT","order":"ASC"}},"operationName":"CasesByPriorityOrdered"}' \
  'query CasesByPriorityOrdered($after: String) { uiapi { aggregate { Case(groupBy: { Priority: { group: true } }, orderBy: { Description: { function: COUNT, order: ASC } }, after: $after) { edges { node { aggregate { Priority { value } countId: Id { count { value } } } } } pageInfo { hasNextPage endCursor } } } } }' \
  "count Cases groupBy Priority, orderBy Description count ASC"

# a119: count Accounts, groupBy Industry + OwnerId, orderBy Description count DESC
check_orderby \
  "a119_accounts_by_industry_and_owner_ordered" \
  '{"org":"ebikes","object":"Account","aggregations":[{"function":"count"}],"groupBy":["Industry","OwnerId"],"orderBy":{"Description":{"function":"COUNT","order":"DESC"}},"operationName":"AccountsByIndustryOwnerOrdered"}' \
  'query AccountsByIndustryOwnerOrdered($after: String) { uiapi { aggregate { Account(groupBy: { Industry: { group: true }, OwnerId: { group: true } }, orderBy: { Description: { function: COUNT, order: DESC } }, after: $after) { edges { node { aggregate { Industry { value } OwnerId { value } countId: Id { count { value } } } } } pageInfo { hasNextPage endCursor } } } } }' \
  "count Accounts groupBy Industry + OwnerId, orderBy Description count DESC"

echo ""
echo "=== Summary: $PASS_COUNT PASS, $FAIL_COUNT FAIL ==="

# Write results file for reflection
cat > "$RESULTS_FILE" <<EOF
# Smoke Test Results — OrderBy
# Run: $(date)
# Pass: $PASS_COUNT / 4
# Fail: $FAIL_COUNT / 4

$DETAILS
EOF

echo "Results written to $RESULTS_FILE"

if [ "$FAIL_COUNT" -gt 0 ]; then
  exit 1
fi
exit 0
