#!/usr/bin/env bash

# E2E Test Runner Script
# Automatically starts RustFS instance, runs tests, and cleans up

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

# Default values
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TARGET_DIR="$PROJECT_ROOT/target/debug"
RUSTFS_BINARY="$TARGET_DIR/rustfs"
DATA_DIR="$TARGET_DIR/rustfs_test_data"
RUSTFS_PID=""
TEST_FILTER=""
TEST_TYPE="all"
RUSTFS_BUILD_FEATURES="${RUSTFS_BUILD_FEATURES:-ftps,webdav,sftp}"
export RUSTFS_BUILD_FEATURES

# Function to print colored output
print_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

print_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Function to show usage
show_usage() {
    cat << EOF
Usage: $0 [OPTIONS]

Options:
    -h, --help              Show this help message
    -t, --test <pattern>    Run specific test(s) matching pattern
    -f, --file <file>       Run all tests in specific file (e.g., sql, basic)
    -a, --all               Run all e2e tests (default)
    
Examples:
    $0                                          # Run all e2e tests
    $0 -t test_select_object_content_csv_basic  # Run specific test
    $0 -f sql                                   # Run all SQL tests
    $0 -f reliant::sql                          # Run all tests in sql.rs file

EOF
}

# Function to cleanup on exit
cleanup() {
    print_info "Cleaning up..."
    
    # Stop RustFS if running
    if [ ! -z "$RUSTFS_PID" ] && kill -0 "$RUSTFS_PID" 2>/dev/null; then
        print_info "Stopping RustFS (PID: $RUSTFS_PID)..."
        kill "$RUSTFS_PID" 2>/dev/null || true
        sleep 2
        
        # Force kill if still running
        if kill -0 "$RUSTFS_PID" 2>/dev/null; then
            print_warning "Force killing RustFS..."
            kill -9 "$RUSTFS_PID" 2>/dev/null || true
        fi
    fi
    
    # Clean up data directory
    if [ -d "$DATA_DIR" ]; then
        print_info "Removing test data directory: $DATA_DIR"
        rm -rf "$DATA_DIR"
    fi
    
    print_success "Cleanup completed"
}

# Set trap to cleanup on exit
trap cleanup EXIT INT TERM

# Function to build RustFS
build_rustfs() {
    print_info "Building RustFS..."
    cd "$PROJECT_ROOT"
    
    if ! cargo build --bin rustfs --features "$RUSTFS_BUILD_FEATURES"; then
        print_error "Failed to build RustFS"
        exit 1
    fi
    
    if [ ! -f "$RUSTFS_BINARY" ]; then
        print_error "RustFS binary not found at: $RUSTFS_BINARY"
        exit 1
    fi
    
    print_success "RustFS built successfully"
}

# Function to check if required tools are available
check_dependencies() {
    local missing_tools=()
    
    if ! command -v curl >/dev/null 2>&1; then
        missing_tools+=("curl")
    fi
    
    if ! command -v cargo >/dev/null 2>&1; then
        missing_tools+=("cargo")
    fi
    
    if [ ${#missing_tools[@]} -gt 0 ]; then
        print_error "Missing required tools: ${missing_tools[*]}"
        print_error "Please install the missing tools and try again"
        exit 1
    fi
}

# Function to start RustFS
start_rustfs() {
    print_info "Starting RustFS instance..."
    
    # Create data directory and logs directory
    mkdir -p "$DATA_DIR"
    mkdir -p "$TARGET_DIR/logs"
    
    # Start RustFS in background with environment variables
    cd "$TARGET_DIR"
    RUSTFS_ACCESS_KEY=rustfsadmin RUSTFS_SECRET_KEY=rustfsadmin \
    RUSTFS_OBS_LOG_DIRECTORY="$TARGET_DIR/logs" \
    ./rustfs --address :9000 "$DATA_DIR" > rustfs.log 2>&1 &
    RUSTFS_PID=$!
    
    print_info "RustFS started with PID: $RUSTFS_PID"
    print_info "Data directory: $DATA_DIR"
    print_info "Log file: $TARGET_DIR/rustfs.log"
    print_info "RustFS logs directory: $TARGET_DIR/logs"
    
    # Wait for RustFS to be ready
    print_info "Waiting for RustFS to be ready..."
    local max_attempts=60
    local attempt=0
    
    while [ $attempt -lt $max_attempts ]; do
        # Check if process is still running first (faster check)
        if ! kill -0 "$RUSTFS_PID" 2>/dev/null; then
            print_error "RustFS process died unexpectedly"
            print_error "Log output:"
            cat "$TARGET_DIR/rustfs.log" || true
            exit 1
        fi
        
        if curl --silent --show-error --fail --noproxy localhost --connect-timeout 2 --max-time 3 \
            "http://localhost:9000/health/ready" >/dev/null 2>&1; then
            print_success "RustFS is ready!"
            return 0
        fi
        
        sleep 1
        attempt=$((attempt + 1))
        echo -n "."
    done
    
    echo
    print_error "RustFS readiness check failed within $max_attempts seconds"
    print_error "Log output:"
    cat "$TARGET_DIR/rustfs.log" || true
    return 1
}

# Function to run tests
run_tests() {
    print_info "Running e2e tests..."
    cd "$PROJECT_ROOT"

    local test_cmd=(cargo test --package e2e_test --lib)

    case "$TEST_TYPE" in
        "specific")
            test_cmd+=(-- "$TEST_FILTER")
            print_info "Running specific test: $TEST_FILTER"
            ;;
        "file")
            test_cmd+=(-- "$TEST_FILTER")
            print_info "Running tests in file/module: $TEST_FILTER"
            ;;
        "all")
            test_cmd+=(--)
            print_info "Running all e2e tests"
            ;;
    esac
    test_cmd+=(--show-output --include-ignored --test-threads=1)

    print_info "Test command: ${test_cmd[*]}"

    if "${test_cmd[@]}"; then
        print_success "All tests passed!"
        return 0
    else
        print_error "Some tests failed!"
        return 1
    fi
}

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_usage
            exit 0
            ;;
        -t|--test)
            TEST_FILTER="$2"
            TEST_TYPE="specific"
            shift 2
            ;;
        -f|--file)
            TEST_FILTER="$2"
            TEST_TYPE="file"
            shift 2
            ;;
        -a|--all)
            TEST_TYPE="all"
            shift
            ;;
        *)
            print_error "Unknown option: $1"
            show_usage
            exit 1
            ;;
    esac
done

# Main execution
main() {
    print_info "Starting E2E Test Runner"
    print_info "Project root: $PROJECT_ROOT"
    print_info "Target directory: $TARGET_DIR"
    
    # Check dependencies
    check_dependencies
    
    # Build RustFS
    build_rustfs
    
    # Start RustFS
    if ! start_rustfs; then
        print_error "Failed to start RustFS properly"
        exit 1
    fi
    
    # Run tests
    local test_result=0
    run_tests || test_result=$?
    
    # Cleanup will be handled by trap
    
    if [ $test_result -eq 0 ]; then
        print_success "E2E tests completed successfully!"
        exit 0
    else
        print_error "E2E tests failed!"
        exit 1
    fi
}

# Run main function
main "$@"
