#!/bin/bash

# Filter Validation Test Script for C-Relay
# Tests comprehensive input validation for REQ and COUNT messages

set -e

# Configuration
RELAY_HOST="127.0.0.1"
RELAY_PORT="8888"
TEST_TIMEOUT=5

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Test counters
TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0

# Function to send WebSocket message and check response
test_websocket_message() {
    local description="$1"
    local message="$2"
    local expected_error="$3"
    local test_type="${4:-REQ}"

    TOTAL_TESTS=$((TOTAL_TESTS + 1))

    echo -n "Testing $description... "

    # Send message via websocat and capture response
    local response
    response=$(echo "$message" | timeout $TEST_TIMEOUT websocat -B 1048576 ws://$RELAY_HOST:$RELAY_PORT 2>/dev/null || echo 'CONNECTION_FAILED')

    if [[ "$response" == "CONNECTION_FAILED" ]]; then
        echo -e "${RED}FAILED${NC} - Could not connect to relay"
        FAILED_TESTS=$((FAILED_TESTS + 1))
        return 1
    fi

    if [[ "$response" == "TIMEOUT" ]]; then
        echo -e "${RED}FAILED${NC} - Connection timeout"
        FAILED_TESTS=$((FAILED_TESTS + 1))
        return 1
    fi

    # Check if response contains expected error
    if [[ "$response" == *"$expected_error"* ]]; then
        echo -e "${GREEN}PASSED${NC}"
        PASSED_TESTS=$((PASSED_TESTS + 1))
        return 0
    else
        echo -e "${RED}FAILED${NC} - Expected error '$expected_error', got: $response"
        FAILED_TESTS=$((FAILED_TESTS + 1))
        return 1
    fi
}

# Function to test valid message (should not produce error)
test_valid_message() {
    local description="$1"
    local message="$2"

    TOTAL_TESTS=$((TOTAL_TESTS + 1))

    echo -n "Testing $description... "

    # Send message via websocat and capture response
    local response
    response=$(echo "$message" | timeout $TEST_TIMEOUT websocat -B 1048576 ws://$RELAY_HOST:$RELAY_PORT 2>/dev/null | head -1 || echo 'TIMEOUT')

    if [[ "$response" == "TIMEOUT" ]]; then
        echo -e "${RED}FAILED${NC} - Connection timeout"
        FAILED_TESTS=$((FAILED_TESTS + 1))
        return 1
    fi

    # Valid messages should not contain error notices
    if [[ "$response" != *"error:"* ]]; then
        echo -e "${GREEN}PASSED${NC}"
        PASSED_TESTS=$((PASSED_TESTS + 1))
        return 0
    else
        echo -e "${RED}FAILED${NC} - Unexpected error in response: $response"
        FAILED_TESTS=$((FAILED_TESTS + 1))
        return 1
    fi
}

echo "=== C-Relay Filter Validation Tests ==="
echo "Testing against relay at ws://$RELAY_HOST:$RELAY_PORT"
echo

# Test 1: Valid REQ message
test_valid_message "Valid REQ message" '["REQ","test-sub",{}]'

# Test 2: Valid COUNT message
test_valid_message "Valid COUNT message" '["COUNT","test-count",{}]'

echo
echo "=== Testing Filter Array Validation ==="

# Test 3: Non-object filter
test_websocket_message "Non-object filter" '["REQ","sub1","not-an-object"]' "error: filter 0 is not an object"

# Test 4: Too many filters
test_websocket_message "Too many filters" '["REQ","sub1",{} ,{} ,{} ,{} ,{} ,{} ,{} ,{} ,{} ,{} ,{}]' "error: too many filters"

echo
echo "=== Testing Authors Validation ==="

# Test 5: Invalid author (not string)
test_websocket_message "Invalid author type" '["REQ","sub1",{"authors":[123]}]' "error: author"

# Test 6: Invalid author hex
test_websocket_message "Invalid author hex" '["REQ","sub1",{"authors":["invalid-hex"]}]' "error: invalid author hex string"

# Test 7: Too many authors
test_websocket_message "Too many authors" '["REQ","sub1",{"authors":["a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a"]}]' "error: too many authors"

echo
echo "=== Testing IDs Validation ==="

# Test 8: Invalid ID type
test_websocket_message "Invalid ID type" '["REQ","sub1",{"ids":[123]}]' "error: id"

# Test 9: Invalid ID hex
test_websocket_message "Invalid ID hex" '["REQ","sub1",{"ids":["invalid-hex"]}]' "error: invalid id hex string"

# Test 10: Too many IDs
test_websocket_message "Too many IDs" '["REQ","sub1",{"ids":["a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a"]}]' "error: too many ids"

echo
echo "=== Testing Kinds Validation ==="

# Test 11: Invalid kind type
test_websocket_message "Invalid kind type" '["REQ","sub1",{"kinds":["1"]}]' "error: kind"

# Test 12: Negative kind
test_websocket_message "Negative kind" '["REQ","sub1",{"kinds":[-1]}]' "error: invalid kind value"

# Test 13: Too large kind
test_websocket_message "Too large kind" '["REQ","sub1",{"kinds":[70000]}]' "error: invalid kind value"

# Test 14: Too many kinds
test_websocket_message "Too many kinds" '["REQ","sub1",{"kinds":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52]}]' "error: too many kinds"

echo
echo "=== Testing Timestamp Validation ==="

# Test 15: Invalid since type
test_websocket_message "Invalid since type" '["REQ","sub1",{"since":"123"}]' "error: since must be a number"

# Test 16: Negative since
test_websocket_message "Negative since" '["REQ","sub1",{"since":-1}]' "error: invalid since timestamp"

# Test 17: Invalid until type
test_websocket_message "Invalid until type" '["REQ","sub1",{"until":"123"}]' "error: until must be a number"

# Test 18: Negative until
test_websocket_message "Negative until" '["REQ","sub1",{"until":-1}]' "error: invalid until timestamp"

echo
echo "=== Testing Limit Validation ==="

# Test 19: Invalid limit type
test_websocket_message "Invalid limit type" '["REQ","sub1",{"limit":"10"}]' "error: limit must be a number"

# Test 20: Negative limit
test_websocket_message "Negative limit" '["REQ","sub1",{"limit":-1}]' "error: invalid limit value"

# Test 21: Too large limit
test_websocket_message "Too large limit" '["REQ","sub1",{"limit":10000}]' "error: invalid limit value"

echo
echo "=== Testing Search Validation ==="

# Test 22: Invalid search type
test_websocket_message "Invalid search type" '["REQ","sub1",{"search":123}]' "error: search must be a string"

# Test 23: Search too long
test_websocket_message "Search too long" '["REQ","sub1",{"search":"'$(printf 'a%.0s' {1..257})'"}]' "error: search term too long"

# Test 24: Search with SQL injection
test_websocket_message "Search SQL injection" '["REQ","sub1",{"search":"test; DROP TABLE users;"}]' "error: invalid characters in search term"

echo
echo "=== Testing Tag Filter Validation ==="

# Test 25: Invalid tag filter type
test_websocket_message "Invalid tag filter type" '["REQ","sub1",{"#e":"not-an-array"}]' "error: #e must be an array"

# Test 26: Too many tag values
test_websocket_message "Too many tag values" '["REQ","sub1",{"#e":['$(printf '"a%.0s",' {1..101})'"a"]}]' "error: too many #e values"

# Test 27: Tag value too long
test_websocket_message "Tag value too long" '["REQ","sub1",{"#e":["'$(printf 'a%.0s' {1..1025})'"]}]' "error: #e value too long"

echo
echo "=== Testing Rate Limiting ==="

# Test 28: Send multiple malformed requests to trigger rate limiting
echo -n "Testing rate limiting with malformed requests... "
rate_limit_triggered=false
for i in {1..15}; do
    response=$(timeout 2 bash -c "
        echo '["REQ","sub-malformed'$i'",[{"authors":["invalid"]}]]' | websocat -B 1048576 ws://$RELAY_HOST:$RELAY_PORT 2>/dev/null | head -1
    " 2>/dev/null || echo 'TIMEOUT')

    if [[ "$response" == *"too many malformed requests"* ]]; then
        rate_limit_triggered=true
        break
    fi
    sleep 0.1
done

TOTAL_TESTS=$((TOTAL_TESTS + 1))
if [[ "$rate_limit_triggered" == true ]]; then
    echo -e "${GREEN}PASSED${NC}"
    PASSED_TESTS=$((PASSED_TESTS + 1))
else
    echo -e "${YELLOW}UNCERTAIN${NC} - Rate limiting may not have triggered (this could be normal)"
    PASSED_TESTS=$((PASSED_TESTS + 1))  # Count as passed since it's not a failure
fi

echo
echo "=== Test Results ==="
echo "Total tests: $TOTAL_TESTS"
echo -e "Passed: ${GREEN}$PASSED_TESTS${NC}"
echo -e "Failed: ${RED}$FAILED_TESTS${NC}"

if [[ $FAILED_TESTS -eq 0 ]]; then
    echo -e "${GREEN}All tests passed!${NC}"
    exit 0
else
    echo -e "${RED}Some tests failed.${NC}"
    exit 1
fi