#!/bin/bash

# Working Authentication System Test Suite
# Tests the unified nostr_core_lib authentication system integrated into ginxsom

# Configuration
SERVER_URL="http://localhost:9001"
UPLOAD_ENDPOINT="${SERVER_URL}/upload"
LIST_ENDPOINT="${SERVER_URL}/list"
DELETE_ENDPOINT="${SERVER_URL}/delete"
DB_PATH="db/ginxsom.db"
TEST_DIR="tests/auth_test_tmp"

# Test keys for different scenarios
TEST_ADMIN_PRIVKEY="993bf9c54fc00bd32a5a1ce64b6d384a5fce109df1e9aee9be1052c1e5cd8120"
TEST_ADMIN_PUBKEY="2ef05348f28d24e0f0ed0751278442c27b62c823c37af8d8d89d8592c6ee84e7"

TEST_USER1_PRIVKEY="5c0c523f52a5b6fad39ed2403092df8cebc36318b39383bca6c00808626fab3a"  
TEST_USER1_PUBKEY="79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"

TEST_USER2_PRIVKEY="182c3a5e3b7a1b7e4f5c6b7c8b4a5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
TEST_USER2_PUBKEY="c95195e5e7de1ad8c4d3c0ac4e8b5c0c4e0c4d3c1e5c8d4c2e7e9f4a5b6c7d8e"

# Test counters
TESTS_PASSED=0
TESTS_FAILED=0
TESTS_TOTAL=0

echo "=== Ginxsom Authentication System Test Suite ==="
echo "Testing unified nostr_core_lib authentication integration"
echo "Timestamp: $(date -Iseconds)"
echo

# Helper functions
test_pass() {
    local test_name="$1"
    ((TESTS_PASSED++))
    ((TESTS_TOTAL++))
    echo "✓ $test_name"
}

test_fail() {
    local test_name="$1"
    local reason="$2"
    ((TESTS_FAILED++))
    ((TESTS_TOTAL++))
    echo "✗ $test_name: $reason"
}

# Check prerequisites
echo "[INFO] Checking prerequisites..."
for cmd in nak curl jq sqlite3; do
    if ! command -v $cmd &> /dev/null; then
        echo "[ERROR] $cmd command not found"
        exit 1
    fi
done

# Check if server is running
if ! curl -s -f "${SERVER_URL}/" > /dev/null 2>&1; then
    echo "[ERROR] Server not running at $SERVER_URL"
    echo "[INFO] Start with: ./restart-all.sh"
    exit 1
fi

# Check if database exists
if [[ ! -f "$DB_PATH" ]]; then
    echo "[ERROR] Database not found at $DB_PATH"
    exit 1
fi

echo "[SUCCESS] All prerequisites met"

# Setup test environment
echo "[INFO] Setting up test environment..."
mkdir -p "$TEST_DIR"

# Enable authentication rules in database
sqlite3 "$DB_PATH" "INSERT OR REPLACE INTO auth_config (key, value) VALUES ('auth_rules_enabled', 'true');"

# Clear any existing test rules
sqlite3 "$DB_PATH" "DELETE FROM auth_rules WHERE description LIKE 'TEST_%' ESCAPE '\';" 2>/dev/null || true
sqlite3 "$DB_PATH" "DELETE FROM auth_cache;" 2>/dev/null || true

echo "[SUCCESS] Test environment ready"

# Generate test file
create_test_file() {
    local filename="$1"
    local size="${2:-1024}"
    local filepath="$TEST_DIR/$filename"
    
    if [[ $size -lt 100 ]]; then
        echo "Small test file $(date)" > "$filepath"
    else
        echo "Test file: $filename" > "$filepath"
        echo "Created: $(date -Iseconds)" >> "$filepath"
        echo "Size target: $size bytes" >> "$filepath"
        dd if=/dev/urandom bs=1 count=$((size - 200)) 2>/dev/null | base64 >> "$filepath"
    fi
    
    echo "$filepath"
}

# Generate nostr event for authentication
create_auth_event() {
    local privkey="$1" 
    local operation="$2"
    local hash="$3"
    local expiration_offset="${4:-3600}"  # 1 hour default
    
    local expiration=$(date -d "+${expiration_offset} seconds" +%s)
    
    local event_args=(-k 24242 -c "" --tag "t=$operation" --tag "expiration=$expiration" --sec "$privkey")
    
    if [[ -n "$hash" ]]; then
        event_args+=(--tag "x=$hash")
    fi
    
    nak event "${event_args[@]}"
}

# Test authenticated upload
test_authenticated_upload() {
    local privkey="$1"
    local operation="$2"
    local file_path="$3"
    local expected_status="$4"
    local test_description="$5"
    
    echo "[TEST] $test_description"
    
    local file_hash=$(sha256sum "$file_path" | cut -d' ' -f1)
    local event=$(create_auth_event "$privkey" "$operation" "$file_hash")
    local auth_header="Nostr $(echo "$event" | base64 -w 0)"
    
    local mime_type=$(file -b --mime-type "$file_path" 2>/dev/null || echo "application/octet-stream")
    
    local response_file=$(mktemp)
    local http_status=$(curl -s -w "%{http_code}" \
        -H "Authorization: $auth_header" \
        -H "Content-Type: $mime_type" \
        --data-binary "@$file_path" \
        -X PUT "$UPLOAD_ENDPOINT" \
        -o "$response_file")
    
    local response_body=$(cat "$response_file")
    rm -f "$response_file"
    
    if [[ "$http_status" == "$expected_status" ]]; then
        test_pass "$test_description (HTTP $http_status)"
        return 0
    else
        test_fail "$test_description" "Expected HTTP $expected_status, got $http_status. Response: $response_body"
        return 1
    fi
}

# Add auth rule to database
add_auth_rule() {
    local rule_type="$1"
    local target="$2"
    local operation="${3:-*}"
    local priority="${4:-100}"
    local description="${5:-TEST_RULE}"
    
    sqlite3 "$DB_PATH" "INSERT INTO auth_rules (rule_type, rule_target, operation, priority, enabled, description) 
                       VALUES ('$rule_type', '$target', '$operation', $priority, 1, '$description');"
}

# Clear test rules
clear_auth_rules() {
    sqlite3 "$DB_PATH" "DELETE FROM auth_rules WHERE description LIKE 'TEST_%' ESCAPE '\';" 2>/dev/null || true
    sqlite3 "$DB_PATH" "DELETE FROM auth_cache;" 2>/dev/null || true
}

echo
echo "=== Test 1: Basic Authentication (Disabled) ==="

# Disable auth rules temporarily
sqlite3 "$DB_PATH" "INSERT OR REPLACE INTO auth_config (key, value) VALUES ('auth_rules_enabled', 'false');"

test_file1=$(create_test_file "basic_test.txt" 500)
test_authenticated_upload "$TEST_USER1_PRIVKEY" "upload" "$test_file1" "200" "Upload without auth rules (disabled)"

# Re-enable auth rules for other tests  
sqlite3 "$DB_PATH" "INSERT OR REPLACE INTO auth_config (key, value) VALUES ('auth_rules_enabled', 'true');"

echo
echo "=== Test 2: Pubkey Whitelist Rules ==="

clear_auth_rules
add_auth_rule "pubkey_whitelist" "$TEST_USER1_PUBKEY" "upload" 10 "TEST_WHITELIST_USER1"

test_file2=$(create_test_file "whitelist_test.txt" 500)
test_authenticated_upload "$TEST_USER1_PRIVKEY" "upload" "$test_file2" "200" "Whitelisted user upload"
test_authenticated_upload "$TEST_USER2_PRIVKEY" "upload" "$test_file2" "403" "Non-whitelisted user upload"

echo
echo "=== Test 3: Pubkey Blacklist Rules ==="

clear_auth_rules
add_auth_rule "pubkey_blacklist" "$TEST_USER2_PUBKEY" "upload" 5 "TEST_BLACKLIST_USER2"

test_file3=$(create_test_file "blacklist_test.txt" 500)
test_authenticated_upload "$TEST_USER1_PRIVKEY" "upload" "$test_file3" "200" "Non-blacklisted user upload"
test_authenticated_upload "$TEST_USER2_PRIVKEY" "upload" "$test_file3" "403" "Blacklisted user upload"

echo
echo "=== Test 4: Hash Blacklist Rules ==="

clear_auth_rules
test_file4=$(create_test_file "hash_blacklist_test.txt" 500)
file_hash4=$(sha256sum "$test_file4" | cut -d' ' -f1)

# Add hash to blacklist
add_auth_rule "hash_blacklist" "$file_hash4" "upload" 5 "TEST_HASH_BLACKLIST"

test_authenticated_upload "$TEST_USER1_PRIVKEY" "upload" "$test_file4" "403" "Blacklisted hash upload"

# Upload of different hash should succeed
test_file4b=$(create_test_file "hash_allowed_test.txt" 600)
test_authenticated_upload "$TEST_USER1_PRIVKEY" "upload" "$test_file4b" "200" "Non-blacklisted hash upload"

echo
echo "=== Test 5: Rule Priority Ordering ==="

clear_auth_rules

# Add conflicting rules with different priorities
add_auth_rule "pubkey_blacklist" "$TEST_USER1_PUBKEY" "upload" 5 "TEST_PRIORITY_BLACKLIST"  # Higher priority (lower number)
add_auth_rule "pubkey_whitelist" "$TEST_USER1_PUBKEY" "upload" 10 "TEST_PRIORITY_WHITELIST" # Lower priority

test_file5=$(create_test_file "priority_test.txt" 500)
test_authenticated_upload "$TEST_USER1_PRIVKEY" "upload" "$test_file5" "403" "Priority test (blacklist > whitelist)"

# Reverse priorities
clear_auth_rules
add_auth_rule "pubkey_whitelist" "$TEST_USER1_PUBKEY" "upload" 5 "TEST_PRIORITY_WHITELIST_HIGH"
add_auth_rule "pubkey_blacklist" "$TEST_USER1_PUBKEY" "upload" 10 "TEST_PRIORITY_BLACKLIST_LOW"

test_authenticated_upload "$TEST_USER1_PRIVKEY" "upload" "$test_file5" "200" "Priority test (whitelist > blacklist)"

echo
echo "=== Cleanup ==="

# Remove temporary files
rm -rf "$TEST_DIR"

# Clean up test auth rules
clear_auth_rules

echo
echo "=== Test Results Summary ==="
echo "Tests Passed: $TESTS_PASSED"
echo "Tests Failed: $TESTS_FAILED"  
echo "Total Tests:  $TESTS_TOTAL"
echo

if [[ $TESTS_FAILED -eq 0 ]]; then
    echo "[SUCCESS] All tests passed! ✓"
    exit 0
else
    echo "[ERROR] $TESTS_FAILED tests failed! ✗"
    exit 1
fi