#!/bin/bash
# ================================================
# Math Platform - End-to-End Testing Script
# ================================================

set -e

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

# Configuration
API_BASE_URL="http://localhost:3001"
FRONTEND_URL="http://localhost:3000"
TEST_USER_EMAIL="test_$(date +%s)@example.com"
TEST_USER_PASSWORD="Test123456!"
TEST_USER_NAME="Test User"

# Test results
TESTS_PASSED=0
TESTS_FAILED=0
TESTS_TOTAL=0

# Helper functions
print_header() {
    echo -e "\n${BLUE}============================================${NC}"
    echo -e "${BLUE}$1${NC}"
    echo -e "${BLUE}============================================${NC}"
}

print_test() {
    echo -e "\n${YELLOW}TEST: $1${NC}"
    TESTS_TOTAL=$((TESTS_TOTAL + 1))
}

print_success() {
    echo -e "${GREEN}✓ PASSED: $1${NC}"
    TESTS_PASSED=$((TESTS_PASSED + 1))
}

print_error() {
    echo -e "${RED}✗ FAILED: $1${NC}"
    TESTS_FAILED=$((TESTS_FAILED + 1))
}

print_info() {
    echo -e "${BLUE}ℹ $1${NC}"
}

# Function to wait for service
wait_for_service() {
    local url=$1
    local max_attempts=30
    local attempt=1

    print_info "Waiting for $url..."

    while [ $attempt -le $max_attempts ]; do
        if curl -s -f "$url" > /dev/null 2>&1; then
            print_success "Service is ready"
            return 0
        fi
        sleep 2
        attempt=$((attempt + 1))
    done

    print_error "Service not ready after $max_attempts attempts"
    return 1
}

# Function to make API request
api_request() {
    local method=$1
    local endpoint=$2
    local data=$3
    local token=$4

    local url="${API_BASE_URL}${endpoint}"
    local headers="-H 'Content-Type: application/json'"

    if [ -n "$token" ]; then
        headers="$headers -H 'Authorization: Bearer $token'"
    fi

    if [ "$method" = "GET" ]; then
        curl -s -X GET "$url" $headers
    elif [ "$method" = "POST" ]; then
        curl -s -X POST "$url" $headers -d "$data"
    elif [ "$method" = "PUT" ]; then
        curl -s -X PUT "$url" $headers -d "$data"
    elif [ "$method" = "DELETE" ]; then
        curl -s -X DELETE "$url" $headers
    fi
}

# Function to test user registration
test_registration() {
    print_test "User Registration"

    local response=$(api_request "POST" "/api/auth/register" "{\"email\":\"$TEST_USER_EMAIL\",\"password\":\"$TEST_USER_PASSWORD\",\"name\":\"$TEST_USER_NAME\"}")

    if echo "$response" | grep -q "token"; then
        USER_TOKEN=$(echo "$response" | grep -o '"token":"[^"]*' | cut -d'"' -f4)
        USER_ID=$(echo "$response" | grep -o '"id":"[^"]*' | cut -d'"' -f4)
        print_success "User registered successfully"
        print_info "User ID: $USER_ID"
        print_info "Email: $TEST_USER_EMAIL"
        return 0
    else
        print_error "Registration failed"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test user login
test_login() {
    print_test "User Login"

    local response=$(api_request "POST" "/api/auth/login" "{\"email\":\"$TEST_USER_EMAIL\",\"password\":\"$TEST_USER_PASSWORD\"}")

    if echo "$response" | grep -q "token"; then
        USER_TOKEN=$(echo "$response" | grep -o '"token":"[^"]*' | cut -d'"' -f4)
        print_success "User logged in successfully"
        return 0
    else
        print_error "Login failed"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test getting modules
test_get_modules() {
    print_test "Get Learning Modules"

    local response=$(api_request "GET" "/api/modules" "" "$USER_TOKEN")

    if echo "$response" | grep -q "modules"; then
        MODULE_COUNT=$(echo "$response" | grep -o '"id"' | wc -l)
        print_success "Retrieved $MODULE_COUNT modules"

        # Get first module ID
        if [ $MODULE_COUNT -gt 0 ]; then
            MODULE_ID=$(echo "$response" | grep -o '"id":"[^"]*' | head -1 | cut -d'"' -f4)
            print_info "First Module ID: $MODULE_ID"
        fi
        return 0
    else
        print_error "Failed to retrieve modules"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test accessing a specific module
test_access_module() {
    print_test "Access Module Content"

    if [ -z "$MODULE_ID" ]; then
        print_error "No module ID available"
        return 1
    fi

    local response=$(api_request "GET" "/api/modules/$MODULE_ID" "" "$USER_TOKEN")

    if echo "$response" | grep -q "title"; then
        MODULE_TITLE=$(echo "$response" | grep -o '"title":"[^"]*' | cut -d'"' -f4)
        print_success "Accessed module: $MODULE_TITLE"
        return 0
    else
        print_error "Failed to access module"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test getting exercises
test_get_exercises() {
    print_test "Get Exercises for Module"

    if [ -z "$MODULE_ID" ]; then
        print_error "No module ID available"
        return 1
    fi

    local response=$(api_request "GET" "/api/exercises?moduleId=$MODULE_ID" "" "$USER_TOKEN")

    if echo "$response" | grep -q "exercises"; then
        EXERCISE_COUNT=$(echo "$response" | grep -o '"id"' | wc -l)
        print_success "Retrieved $EXERCISE_COUNT exercises"

        # Get first exercise ID
        if [ $EXERCISE_COUNT -gt 0 ]; then
            EXERCISE_ID=$(echo "$response" | grep -o '"id":"[^"]*' | head -1 | cut -d'"' -f4)
            print_info "First Exercise ID: $EXERCISE_ID"
        fi
        return 0
    else
        print_error "Failed to retrieve exercises"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test submitting an exercise
test_submit_exercise() {
    print_test "Submit Exercise Answer"

    if [ -z "$EXERCISE_ID" ]; then
        print_error "No exercise ID available"
        return 1
    fi

    # Submit a test answer
    local response=$(api_request "POST" "/api/exercises/$EXERCISE_ID/submit" "{\"answer\":\"42\",\"timeSpent\":60}" "$USER_TOKEN")

    if echo "$response" | grep -q "correct"; then
        print_success "Exercise submitted successfully"
        return 0
    else
        print_error "Failed to submit exercise"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test getting user progress
test_get_progress() {
    print_test "Get User Progress"

    local response=$(api_request "GET" "/api/users/progress" "" "$USER_TOKEN")

    if echo "$response" | grep -q "progress"; then
        print_success "Retrieved user progress"
        return 0
    else
        print_error "Failed to retrieve progress"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test getting ranking
test_get_ranking() {
    print_test "Get User Ranking"

    local response=$(api_request "GET" "/api/users/ranking?limit=10" "" "$USER_TOKEN")

    if echo "$response" | grep -q "ranking"; then
        print_success "Retrieved user ranking"
        return 0
    else
        print_error "Failed to retrieve ranking"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test getting achievements
test_get_achievements() {
    print_test "Get User Achievements"

    local response=$(api_request "GET" "/api/users/achievements" "" "$USER_TOKEN")

    if echo "$response" | grep -q "achievements"; then
        ACHIEVEMENT_COUNT=$(echo "$response" | grep -o '"id"' | wc -l)
        print_success "Retrieved $ACHIEVEMENT_COUNT achievements"
        return 0
    else
        print_error "Failed to retrieve achievements"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test updating user profile
test_update_profile() {
    print_test "Update User Profile"

    local new_name="Updated Test User"
    local response=$(api_request "PUT" "/api/users/profile" "{\"name\":\"$new_name\"}" "$USER_TOKEN")

    if echo "$response" | grep -q "name"; then
        print_success "Profile updated successfully"
        return 0
    else
        print_error "Failed to update profile"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test health endpoint
test_health() {
    print_test "Health Check Endpoint"

    local response=$(curl -s "$API_BASE_URL/health")

    if echo "$response" | grep -q "status.*ok\|healthy"; then
        print_success "Health check passed"
        return 0
    else
        print_error "Health check failed"
        print_info "Response: $response"
        return 1
    fi
}

# Function to test frontend accessibility
test_frontend() {
    print_test "Frontend Accessibility"

    local response=$(curl -s -o /dev/null -w "%{http_code}" "$FRONTEND_URL")

    if [ "$response" = "200" ]; then
        print_success "Frontend is accessible"
        return 0
    else
        print_error "Frontend returned status code: $response"
        return 1
    fi
}

# Function to run all tests
run_all_tests() {
    print_header "Math Platform E2E Test Suite"

    # Check if services are running
    print_info "Checking service availability..."
    if ! wait_for_service "$API_BASE_URL/health"; then
        print_error "Backend service is not available. Please start the services first."
        print_info "Run: ./docker/start.sh"
        exit 1
    fi

    if ! wait_for_service "$FRONTEND_URL"; then
        print_error "Frontend service is not available. Please start the services first."
        print_info "Run: ./docker/start.sh"
        exit 1
    fi

    echo -e "\n${GREEN}All services are running! Starting tests...${NC}\n"

    # Run tests
    test_health
    test_frontend
    test_registration
    test_login
    test_get_modules
    test_access_module
    test_get_exercises
    test_submit_exercise
    test_get_progress
    test_get_ranking
    test_get_achievements
    test_update_profile

    # Print summary
    print_header "Test Summary"
    echo -e "Total Tests: $TESTS_TOTAL"
    echo -e "${GREEN}Passed: $TESTS_PASSED${NC}"
    echo -e "${RED}Failed: $TESTS_FAILED${NC}"

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

# Function to run specific test
run_specific_test() {
    local test_name=$1

    case $test_name in
        "health")
            test_health
            ;;
        "frontend")
            test_frontend
            ;;
        "register")
            test_registration
            ;;
        "login")
            test_login
            ;;
        "modules")
            test_get_modules
            ;;
        "module")
            test_access_module
            ;;
        "exercises")
            test_get_exercises
            ;;
        "submit")
            test_submit_exercise
            ;;
        "progress")
            test_get_progress
            ;;
        "ranking")
            test_get_ranking
            ;;
        "achievements")
            test_get_achievements
            ;;
        "profile")
            test_update_profile
            ;;
        *)
            print_error "Unknown test: $test_name"
            echo "Available tests: health, frontend, register, login, modules, module, exercises, submit, progress, ranking, achievements, profile"
            exit 1
            ;;
    esac
}

# Main execution
main() {
    if [ $# -eq 0 ]; then
        run_all_tests
    else
        run_specific_test "$1"
    fi
}

# Run main function
main "$@"
