#!/bin/bash
set -e

echo "🚀 Concurrent Booking Stress Test"
echo "================================="

# Configuration
BASE_URL=${BASE_URL:-"http://127.0.0.1:8000"}
EVENT_ID=${EVENT_ID:-123}
CONCURRENT_USERS=${CONCURRENT_USERS:-20}
TEST_DURATION=${TEST_DURATION:-30}
RESULTS_DIR="./stress-test-results"

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# Test seats - focus on contention for premium seats
HIGH_DEMAND_SEATS=("A-01" "A-02" "A-03" "B-01" "B-02" "B-03" "C-01" "C-02")

# Metrics tracking
SUCCESS_COUNT=0
CONFLICT_COUNT=0
ERROR_COUNT=0
RATE_LIMIT_COUNT=0
TOTAL_REQUESTS=0

# Create results directory
mkdir -p "$RESULTS_DIR"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
LOG_FILE="$RESULTS_DIR/stress-test-$TIMESTAMP.log"

echo "📊 Test Configuration:" | tee "$LOG_FILE"
echo "  Base URL: $BASE_URL" | tee -a "$LOG_FILE"
echo "  Event ID: $EVENT_ID" | tee -a "$LOG_FILE"
echo "  Concurrent Users: $CONCURRENT_USERS" | tee -a "$LOG_FILE"
echo "  Test Duration: ${TEST_DURATION}s" | tee -a "$LOG_FILE"
echo "  High Demand Seats: ${HIGH_DEMAND_SEATS[*]}" | tee -a "$LOG_FILE"
echo "" | tee -a "$LOG_FILE"

# Check server availability
echo "🔍 Checking server availability..." | tee -a "$LOG_FILE"
if ! curl -s --connect-timeout 5 "$BASE_URL/api/seats/availability/$EVENT_ID" >/dev/null; then
    echo -e "${RED}❌ Server not accessible at $BASE_URL${NC}" | tee -a "$LOG_FILE"
    exit 1
fi
echo -e "${GREEN}✅ Server is accessible${NC}" | tee -a "$LOG_FILE"
echo "" | tee -a "$LOG_FILE"

# Function to simulate a single user booking attempt
simulate_user() {
    local user_id=$1
    local session_id="stress_test_${user_id}_$$"
    
    # Random seat selection with bias toward high-demand seats
    local seat_index=$((RANDOM % ${#HIGH_DEMAND_SEATS[@]}))
    local seat="${HIGH_DEMAND_SEATS[$seat_index]}"
    
    # Track timing
    local start_time=$(date +%s%3N)
    
    # Make booking request
    local response=$(curl -s -w "%{http_code}" \
        -H "Content-Type: application/json" \
        -H "Cookie: session_id=$session_id" \
        -X POST \
        --connect-timeout 10 \
        --max-time 15 \
        -d "{\"event_id\":$EVENT_ID,\"seat_ids\":[\"$seat\"]}" \
        "$BASE_URL/api/seats/hold" 2>/dev/null)
    
    local end_time=$(date +%s%3N)
    local duration=$((end_time - start_time))
    local http_code="${response: -3}"
    local response_body="${response%???}"
    
    # Log result
    echo "[User-$user_id] Seat: $seat | Status: $http_code | Duration: ${duration}ms | Time: $(date '+%H:%M:%S')" >> "$LOG_FILE"
    
    # Update counters
    TOTAL_REQUESTS=$((TOTAL_REQUESTS + 1))
    case $http_code in
        200|201)
            SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
            # Simulate holding the seat for a brief period
            sleep $(echo "scale=2; $RANDOM / 32767 * 3" | bc -l)
            ;;
        409)
            CONFLICT_COUNT=$((CONFLICT_COUNT + 1))
            ;;
        429)
            RATE_LIMIT_COUNT=$((RATE_LIMIT_COUNT + 1))
            # Back off briefly when rate limited
            sleep 1
            ;;
        *)
            ERROR_COUNT=$((ERROR_COUNT + 1))
            ;;
    esac
}

# Function to run stress test for a duration
run_stress_test() {
    echo "🔥 Starting stress test with $CONCURRENT_USERS concurrent users for ${TEST_DURATION}s..." | tee -a "$LOG_FILE"
    echo "" | tee -a "$LOG_FILE"
    
    local end_time=$(($(date +%s) + TEST_DURATION))
    local pids=()
    
    # Start concurrent user simulations
    for ((user=1; user<=CONCURRENT_USERS; user++)); do
        (
            while [ $(date +%s) -lt $end_time ]; do
                simulate_user $user
                # Small random delay between requests
                sleep $(echo "scale=2; $RANDOM / 32767 * 0.5" | bc -l)
            done
        ) &
        pids+=($!)
        
        # Stagger user starts slightly
        sleep 0.1
    done
    
    echo "🚀 All $CONCURRENT_USERS users started, running for ${TEST_DURATION}s..." | tee -a "$LOG_FILE"
    
    # Show progress
    for ((i=1; i<=TEST_DURATION; i++)); do
        sleep 1
        local progress=$((i * 100 / TEST_DURATION))
        printf "\r⏱️  Progress: [%-20s] %d%% (%ds/%ds)" \
            $(printf '#%.0s' $(seq 1 $((progress / 5)))) \
            $progress $i $TEST_DURATION
    done
    echo ""
    
    # Wait for all users to complete
    echo "⏳ Waiting for all users to complete..." | tee -a "$LOG_FILE"
    for pid in "${pids[@]}"; do
        wait $pid 2>/dev/null || true
    done
}

# Function to analyze results
analyze_results() {
    echo "" | tee -a "$LOG_FILE"
    echo "📊 STRESS TEST RESULTS" | tee -a "$LOG_FILE"
    echo "======================" | tee -a "$LOG_FILE"
    echo "" | tee -a "$LOG_FILE"
    
    # Calculate metrics
    local success_rate=$(echo "scale=2; $SUCCESS_COUNT * 100 / $TOTAL_REQUESTS" | bc -l)
    local conflict_rate=$(echo "scale=2; $CONFLICT_COUNT * 100 / $TOTAL_REQUESTS" | bc -l)
    local error_rate=$(echo "scale=2; $ERROR_COUNT * 100 / $TOTAL_REQUESTS" | bc -l)
    local rate_limit_rate=$(echo "scale=2; $RATE_LIMIT_COUNT * 100 / $TOTAL_REQUESTS" | bc -l)
    local throughput=$(echo "scale=2; $TOTAL_REQUESTS / $TEST_DURATION" | bc -l)
    
    echo "📈 Request Metrics:" | tee -a "$LOG_FILE"
    echo "  Total Requests: $TOTAL_REQUESTS" | tee -a "$LOG_FILE"
    echo "  Successful Bookings: $SUCCESS_COUNT (${success_rate}%)" | tee -a "$LOG_FILE"
    echo "  Seat Conflicts: $CONFLICT_COUNT (${conflict_rate}%)" | tee -a "$LOG_FILE"
    echo "  Rate Limited: $RATE_LIMIT_COUNT (${rate_limit_rate}%)" | tee -a "$LOG_FILE"
    echo "  Errors: $ERROR_COUNT (${error_rate}%)" | tee -a "$LOG_FILE"
    echo "  Throughput: ${throughput} req/s" | tee -a "$LOG_FILE"
    echo "" | tee -a "$LOG_FILE"
    
    # Performance thresholds
    echo "🎯 Performance Assessment:" | tee -a "$LOG_FILE"
    
    if (( $(echo "$success_rate > 70" | bc -l) )); then
        echo -e "  Success Rate: ${GREEN}GOOD${NC} (${success_rate}% > 70%)" | tee -a "$LOG_FILE"
    elif (( $(echo "$success_rate > 50" | bc -l) )); then
        echo -e "  Success Rate: ${YELLOW}OK${NC} (${success_rate}% > 50%)" | tee -a "$LOG_FILE"
    else
        echo -e "  Success Rate: ${RED}POOR${NC} (${success_rate}% < 50%)" | tee -a "$LOG_FILE"
    fi
    
    if (( $(echo "$conflict_rate < 30" | bc -l) )); then
        echo -e "  Conflict Rate: ${GREEN}GOOD${NC} (${conflict_rate}% < 30%)" | tee -a "$LOG_FILE"
    elif (( $(echo "$conflict_rate < 50" | bc -l) )); then
        echo -e "  Conflict Rate: ${YELLOW}OK${NC} (${conflict_rate}% < 50%)" | tee -a "$LOG_FILE"
    else
        echo -e "  Conflict Rate: ${RED}HIGH${NC} (${conflict_rate}% > 50%)" | tee -a "$LOG_FILE"
    fi
    
    if (( $(echo "$error_rate < 5" | bc -l) )); then
        echo -e "  Error Rate: ${GREEN}GOOD${NC} (${error_rate}% < 5%)" | tee -a "$LOG_FILE"
    elif (( $(echo "$error_rate < 10" | bc -l) )); then
        echo -e "  Error Rate: ${YELLOW}OK${NC} (${error_rate}% < 10%)" | tee -a "$LOG_FILE"
    else
        echo -e "  Error Rate: ${RED}HIGH${NC} (${error_rate}% > 10%)" | tee -a "$LOG_FILE"
    fi
    
    if (( $(echo "$throughput > 10" | bc -l) )); then
        echo -e "  Throughput: ${GREEN}GOOD${NC} (${throughput} req/s > 10)" | tee -a "$LOG_FILE"
    elif (( $(echo "$throughput > 5" | bc -l) )); then
        echo -e "  Throughput: ${YELLOW}OK${NC} (${throughput} req/s > 5)" | tee -a "$LOG_FILE"
    else
        echo -e "  Throughput: ${RED}LOW${NC} (${throughput} req/s < 5)" | tee -a "$LOG_FILE"
    fi
}

# Function to check system state after test
check_system_state() {
    echo "" | tee -a "$LOG_FILE"
    echo "🔍 System State Check:" | tee -a "$LOG_FILE"
    echo "=====================" | tee -a "$LOG_FILE"
    
    # Check current availability
    local availability_response=$(curl -s "$BASE_URL/api/seats/availability/$EVENT_ID" 2>/dev/null)
    local available_count=$(echo "$availability_response" | jq -r '.data.count // 0' 2>/dev/null || echo "unknown")
    
    echo "  Available seats after test: $available_count" | tee -a "$LOG_FILE"
    
    # Check if monitoring endpoint shows any errors
    local monitoring_response=$(curl -s "$BASE_URL/monitoring/api" 2>/dev/null)
    local recent_errors=$(echo "$monitoring_response" | jq -r '.errors_last_hour // 0' 2>/dev/null || echo "unknown")
    
    echo "  Errors in last hour: $recent_errors" | tee -a "$LOG_FILE"
}

# Main execution
main() {
    local test_type=${1:-"default"}
    
    case "$test_type" in
        "light")
            CONCURRENT_USERS=10
            TEST_DURATION=15
            ;;
        "medium")
            CONCURRENT_USERS=30
            TEST_DURATION=45
            ;;
        "heavy")
            CONCURRENT_USERS=50
            TEST_DURATION=60
            ;;
        "extreme")
            CONCURRENT_USERS=100
            TEST_DURATION=30
            ;;
        "default"|*)
            # Use default values
            ;;
    esac
    
    run_stress_test
    analyze_results
    check_system_state
    
    echo "" | tee -a "$LOG_FILE"
    echo "✅ Stress test completed!" | tee -a "$LOG_FILE"
    echo "📄 Full results: $LOG_FILE" | tee -a "$LOG_FILE"
    echo ""
}

# Show help
show_help() {
    echo "Usage: $0 [test-type]"
    echo ""
    echo "Test Types:"
    echo "  light    - 10 users, 15s (gentle load)"
    echo "  default  - 20 users, 30s (moderate load)"  
    echo "  medium   - 30 users, 45s (heavy load)"
    echo "  heavy    - 50 users, 60s (stress test)"
    echo "  extreme  - 100 users, 30s (breaking point)"
    echo ""
    echo "Environment Variables:"
    echo "  BASE_URL           - Server URL (default: http://127.0.0.1:8000)"
    echo "  EVENT_ID           - Event ID (default: 123)"
    echo "  CONCURRENT_USERS   - Override concurrent users"
    echo "  TEST_DURATION      - Override test duration (seconds)"
    echo ""
    echo "Examples:"
    echo "  $0                 # Run default test"
    echo "  $0 extreme         # Run extreme stress test"
    echo "  CONCURRENT_USERS=50 $0 # Custom concurrent users"
}

# Handle command line arguments
case "${1:-}" in
    "-h"|"--help")
        show_help
        exit 0
        ;;
    *)
        main "$@"
        ;;
esac