//! Comprehensive REPL tests to boost coverage from 8.33% to 50%+
//! Focus on all public methods and edge cases

#![allow(warnings)] // Test file

use ruchy::runtime::repl::{Repl, ReplConfig, Value};
use std::time::{Duration, Instant};

/// Test basic REPL creation and configuration
#[test]
fn test_repl_creation() {
    // Default creation
    let repl = Repl::new();
    assert!(repl.is_ok());
    
    // With custom config
    let config = ReplConfig {
        max_memory: 10_000_000,
        timeout: Duration::from_millis(100),
        max_depth: 1000,
        debug: false,
    };
    let repl = Repl::with_config(config);
    assert!(repl.is_ok());
}

/// Test evaluate_expr_str method
#[test]
fn test_evaluate_expr_str() {
    let mut repl = Repl::new().unwrap();
    
    // Simple arithmetic
    let result = repl.evaluate_expr_str("2 + 3", None).unwrap();
    assert_eq!(result, Value::Int(5));
    
    // With deadline
    let deadline = Some(Instant::now() + Duration::from_secs(1));
    let result = repl.evaluate_expr_str("5 * 6", deadline).unwrap();
    assert_eq!(result, Value::Int(30));
    
    // String expression
    let result = repl.evaluate_expr_str("\"hello\"", None).unwrap();
    if let Value::String(s) = result {
        assert_eq!(s, "hello");
    } else {
        panic!("Expected string");
    }
    
    // Boolean expression
    let result = repl.evaluate_expr_str("true && false", None).unwrap();
    assert_eq!(result, Value::Bool(false));
    
    // List expression
    let result = repl.evaluate_expr_str("[1, 2, 3]", None).unwrap();
    if let Value::List(list) = result {
        assert_eq!(list.len(), 3);
    } else {
        panic!("Expected list");
    }
}

/// Test eval method (string output)
#[test]
fn test_eval_method() {
    let mut repl = Repl::new().unwrap();
    
    // Simple expressions
    assert_eq!(repl.eval("42").unwrap(), "42");
    assert_eq!(repl.eval("true").unwrap(), "true");
    assert_eq!(repl.eval("\"test\"").unwrap(), "\"test\"");
    
    // Arithmetic
    assert_eq!(repl.eval("10 + 5").unwrap(), "15");
    assert_eq!(repl.eval("20 - 8").unwrap(), "12");
    assert_eq!(repl.eval("3 * 7").unwrap(), "21");
    assert_eq!(repl.eval("15 / 3").unwrap(), "5");
    
    // Variables
    repl.eval("let x = 100").unwrap();
    assert_eq!(repl.eval("x").unwrap(), "100");
    
    // Functions
    repl.eval("fun double(n) { n * 2 }").unwrap();
    assert_eq!(repl.eval("double(21)").unwrap(), "42");
}

/// Test REPL commands
#[test]
fn test_repl_commands() {
    let mut repl = Repl::new().unwrap();
    
    // Test :help command
    let should_exit = repl.handle_command(":help").unwrap();
    assert!(!should_exit);
    
    // Test :clear command
    let should_exit = repl.handle_command(":clear").unwrap();
    assert!(!should_exit);
    
    // Test :reset command
    repl.eval("let x = 42").unwrap();
    let should_exit = repl.handle_command(":reset").unwrap();
    assert!(!should_exit);
    // Variable should be gone after reset
    assert!(repl.eval("x").is_err());
    
    // Test :type command
    repl.eval("let y = 100").unwrap();
    let should_exit = repl.handle_command(":type y").unwrap();
    assert!(!should_exit);
    
    // Test :exit command
    let should_exit = repl.handle_command(":exit").unwrap();
    assert!(should_exit);
    
    // Test :quit command
    let should_exit = repl.handle_command(":quit").unwrap();
    assert!(should_exit);
}

/// Test needs_continuation method
#[test]
fn test_needs_continuation() {
    // Should need continuation
    assert!(Repl::needs_continuation("fun test() {"));
    assert!(Repl::needs_continuation("if true {"));
    assert!(Repl::needs_continuation("match x {"));
    assert!(Repl::needs_continuation("[1, 2,"));
    assert!(Repl::needs_continuation("let x ="));
    
    // Should not need continuation
    assert!(!Repl::needs_continuation("42"));
    assert!(!Repl::needs_continuation("fun test() { 42 }"));
    assert!(!Repl::needs_continuation("if true { 1 } else { 2 }"));
    assert!(!Repl::needs_continuation("[1, 2, 3]"));
    assert!(!Repl::needs_continuation("let x = 42"));
}

/// Test multiline input
#[test]
fn test_multiline_input() {
    let mut repl = Repl::new().unwrap();
    
    // Multiline function
    repl.eval("fun factorial(n) {").unwrap_err(); // Should need continuation
    
    // This would need interactive input handling, so we test complete multiline
    let multiline = "fun factorial(n) {
        if n <= 1 {
            1
        } else {
            n * factorial(n - 1)
        }
    }";
    repl.eval(multiline).unwrap();
    
    assert_eq!(repl.eval("factorial(5)").unwrap(), "120");
}

/// Test error handling
#[test]
fn test_error_handling() {
    let mut repl = Repl::new().unwrap();
    
    // Undefined variable
    assert!(repl.eval("undefined_var").is_err());
    
    // Syntax error
    assert!(repl.eval("fun (").is_err());
    
    // Type error
    assert!(repl.eval("true + 5").is_err());
    
    // Division by zero
    assert!(repl.eval("5 / 0").is_err());
    
    // Invalid command
    assert!(repl.handle_command(":invalid").is_err());
}

/// Test complex expressions
#[test]
fn test_complex_expressions() {
    let mut repl = Repl::new().unwrap();
    
    // Nested expressions
    assert_eq!(repl.eval("(1 + 2) * (3 + 4)").unwrap(), "21");
    
    // String operations
    assert_eq!(repl.eval("\"hello\" + \" \" + \"world\"").unwrap(), "\"hello world\"");
    
    // List operations
    let result = repl.eval("[1, 2, 3] + [4, 5]").unwrap();
    assert!(result.contains("1") && result.contains("5"));
    
    // Object/struct (if supported)
    let _obj_result = repl.eval("{ x: 10, y: 20 }");
    // May or may not be supported
    
    // Lambda expressions
    repl.eval("let add = |a, b| a + b").unwrap();
    assert_eq!(repl.eval("add(15, 27)").unwrap(), "42");
}

/// Test control flow
#[test]
fn test_control_flow() {
    let mut repl = Repl::new().unwrap();
    
    // If-else
    assert_eq!(repl.eval("if true { 1 } else { 0 }").unwrap(), "1");
    assert_eq!(repl.eval("if false { 1 } else { 0 }").unwrap(), "0");
    
    // Match
    repl.eval("let x = 2").unwrap();
    let match_expr = "match x {
        1 => \"one\",
        2 => \"two\",
        _ => \"other\"
    }";
    assert_eq!(repl.eval(match_expr).unwrap(), "\"two\"");
    
    // For loop
    repl.eval("let mut sum = 0").unwrap();
    repl.eval("for i in 1..=5 { sum = sum + i }").unwrap();
    assert_eq!(repl.eval("sum").unwrap(), "15");
    
    // While loop
    repl.eval("let mut count = 0").unwrap();
    repl.eval("while count < 3 { count = count + 1 }").unwrap();
    assert_eq!(repl.eval("count").unwrap(), "3");
}

/// Test special values
#[test]
fn test_special_values() {
    let mut repl = Repl::new().unwrap();
    
    // nil/null
    assert_eq!(repl.eval("nil").unwrap(), "nil");
    
    // Infinity (if supported)
    let _inf_result = repl.eval("1.0 / 0.0");
    // May be inf or error
    
    // NaN (if supported)
    let _nan_result = repl.eval("0.0 / 0.0");
    // May be NaN or error
    
    // Very large numbers
    assert!(repl.eval("999999999999999999").is_ok());
    
    // Very small numbers
    assert!(repl.eval("0.000000000000001").is_ok());
}

/// Test REPL state management
#[test]
fn test_state_management() {
    let mut repl = Repl::new().unwrap();
    
    // Define multiple variables
    repl.eval("let a = 1").unwrap();
    repl.eval("let b = 2").unwrap();
    repl.eval("let c = 3").unwrap();
    
    // They should all be accessible
    assert_eq!(repl.eval("a + b + c").unwrap(), "6");
    
    // Redefine variable
    repl.eval("let a = 10").unwrap();
    assert_eq!(repl.eval("a").unwrap(), "10");
    
    // Mutable variables
    repl.eval("let mut counter = 0").unwrap();
    repl.eval("counter = counter + 1").unwrap();
    repl.eval("counter = counter + 1").unwrap();
    assert_eq!(repl.eval("counter").unwrap(), "2");
}

/// Test function definitions
#[test]
fn test_function_definitions() {
    let mut repl = Repl::new().unwrap();
    
    // Simple function
    repl.eval("fun greet(name) { \"Hello, \" + name }").unwrap();
    assert_eq!(repl.eval("greet(\"World\")").unwrap(), "\"Hello, World\"");
    
    // Recursive function
    repl.eval("fun fib(n) { if n <= 1 { n } else { fib(n-1) + fib(n-2) } }").unwrap();
    assert_eq!(repl.eval("fib(10)").unwrap(), "55");
    
    // Higher-order function
    repl.eval("fun apply(f, x) { f(x) }").unwrap();
    repl.eval("fun square(x) { x * x }").unwrap();
    assert_eq!(repl.eval("apply(square, 6)").unwrap(), "36");
    
    // Closure
    repl.eval("fun make_adder(x) { |y| x + y }").unwrap();
    repl.eval("let add5 = make_adder(5)").unwrap();
    assert_eq!(repl.eval("add5(10)").unwrap(), "15");
}

/// Test edge cases and boundary conditions
#[test]
fn test_edge_cases() {
    let mut repl = Repl::new().unwrap();
    
    // Empty input
    assert!(repl.eval("").is_err() || repl.eval("").unwrap() == "");
    
    // Just whitespace
    assert!(repl.eval("   \n\t  ").is_err() || repl.eval("   \n\t  ").unwrap() == "");
    
    // Very long identifier
    let long_name = "a".repeat(1000);
    let _result = repl.eval(&format!("let {} = 42", long_name));
    // Should either work or fail gracefully
    
    // Very deep nesting
    let nested = "(".repeat(100) + "42" + &")".repeat(100);
    let nested_result = repl.eval(&nested);
    if nested_result.is_ok() {
        assert_eq!(nested_result.unwrap(), "42");
    }
    
    // Unicode in strings
    assert_eq!(repl.eval("\"Hello 世界 🌍\"").unwrap(), "\"Hello 世界 🌍\"");
    
    // Comments (if supported)
    let _with_comment = repl.eval("42 // this is a comment");
    // Should either parse as 42 or fail
}

/// Test performance with deadline
#[test]
fn test_deadline_handling() {
    let mut repl = Repl::new().unwrap();
    
    // Very short deadline (might timeout)
    let deadline = Some(Instant::now() + Duration::from_micros(1));
    let _result = repl.evaluate_expr_str("1 + 1", deadline);
    // Should either complete or timeout gracefully
    
    // Reasonable deadline
    let deadline = Some(Instant::now() + Duration::from_secs(1));
    let result = repl.evaluate_expr_str("2 + 2", deadline).unwrap();
    assert_eq!(result, Value::Int(4));
    
    // No deadline
    let result = repl.evaluate_expr_str("3 + 3", None).unwrap();
    assert_eq!(result, Value::Int(6));
}

/// Test string interpolation
#[test]
fn test_string_interpolation() {
    let mut repl = Repl::new().unwrap();
    
    repl.eval("let name = \"Ruchy\"").unwrap();
    repl.eval("let age = 1").unwrap();
    
    let result = repl.eval("f\"Hello, {name}! You are {age} year old.\"").unwrap();
    assert!(result.contains("Ruchy"));
    assert!(result.contains("1"));
}

/// Test type system features
#[test]
fn test_type_features() {
    let mut repl = Repl::new().unwrap();
    
    // Type annotations (if supported)
    let result = repl.eval("let x: i32 = 42");
    if result.is_ok() {
        assert_eq!(repl.eval("x").unwrap(), "42");
    }
    
    // Generic types (if supported)
    let _result = repl.eval("let list: Vec<i32> = [1, 2, 3]");
    // May or may not be supported
    
    // Type inference
    repl.eval("let inferred = 3.14").unwrap();
    // Should infer as float
}

/// Test import/export (if supported)
#[test]
fn test_imports() {
    let mut repl = Repl::new().unwrap();
    
    // Try to import something
    let _result = repl.eval("import { sqrt } from \"math\"");
    // May or may not be supported
    
    let _result = repl.eval("use std::collections::HashMap");
    // May or may not be supported
}