//! Comprehensive tests for list support (Issue #25)
//!
//! Tests cover:
//! - Empty lists
//! - Single and multiple element lists
//! - Cons operator
//! - List operations (head, tail, isEmpty)
//! - Nested lists
//! - Pattern matching over lists

use fusabi_frontend::ast::{Expr, Literal};
use fusabi_frontend::compiler::Compiler;
use fusabi_frontend::lexer::Lexer;
use fusabi_frontend::parser::Parser;
use fusabi_vm::value::Value;
use fusabi_vm::vm::Vm;

// Helper to parse source code
fn parse(input: &str) -> Result<Expr, String> {
    let mut lexer = Lexer::new(input);
    let tokens = lexer.tokenize().map_err(|e| format!("{}", e))?;
    let mut parser = Parser::new(tokens);
    parser.parse().map_err(|e| format!("{}", e))
}

// Helper to compile and run
fn run(input: &str) -> Result<Value, String> {
    let ast = parse(input)?;
    let chunk = Compiler::compile(&ast).map_err(|e| format!("{}", e))?;
    let mut vm = Vm::new();
    vm.execute(chunk).map_err(|e| format!("{}", e))
}

#[test]
fn test_parse_empty_list() {
    let expr = parse("[]").unwrap();
    assert!(expr.is_list());
    match expr {
        Expr::List(elements) => assert_eq!(elements.len(), 0),
        _ => panic!("Expected List"),
    }
}

#[test]
fn test_parse_single_element_list() {
    let expr = parse("[1]").unwrap();
    assert!(expr.is_list());
    match expr {
        Expr::List(elements) => {
            assert_eq!(elements.len(), 1);
            assert!(elements[0].is_literal());
        }
        _ => panic!("Expected List"),
    }
}

#[test]
fn test_parse_multiple_element_list() {
    let expr = parse("[1; 2; 3]").unwrap();
    assert!(expr.is_list());
    match expr {
        Expr::List(elements) => assert_eq!(elements.len(), 3),
        _ => panic!("Expected List"),
    }
}

#[test]
fn test_parse_list_with_expressions() {
    let expr = parse("[1 + 2; 3 * 4]").unwrap();
    assert!(expr.is_list());
    match expr {
        Expr::List(elements) => {
            assert_eq!(elements.len(), 2);
            assert!(elements[0].is_binop());
            assert!(elements[1].is_binop());
        }
        _ => panic!("Expected List"),
    }
}

#[test]
fn test_parse_cons_operator() {
    let expr = parse("1 :: []").unwrap();
    assert!(expr.is_cons());
}

#[test]
fn test_parse_cons_right_associative() {
    // 1 :: 2 :: [] should parse as 1 :: (2 :: [])
    let expr = parse("1 :: 2 :: []").unwrap();
    match expr {
        Expr::Cons { head, tail } => {
            assert!(tail.is_cons());
        }
        _ => panic!("Expected Cons"),
    }
}

#[test]
fn test_parse_cons_with_list() {
    let expr = parse("1 :: [2; 3]").unwrap();
    match expr {
        Expr::Cons { head, tail } => {
            assert!(head.is_literal());
            assert!(tail.is_list());
        }
        _ => panic!("Expected Cons"),
    }
}

#[test]
fn test_empty_list_value() {
    let result = run("[]").unwrap();
    match result {
        Value::List(None) => {} // Empty list
        _ => panic!("Expected empty list, got {:?}", result),
    }
}

#[test]
fn test_single_element_list_value() {
    let result = run("[42]").unwrap();
    match result {
        Value::List(Some(node)) => {
            assert_eq!(node.head, Value::Int(42));
            assert!(node.tail.is_none());
        }
        _ => panic!("Expected list with one element, got {:?}", result),
    }
}

#[test]
fn test_multiple_element_list_value() {
    let result = run("[1; 2; 3]").unwrap();
    match result {
        Value::List(Some(node)) => {
            assert_eq!(node.head, Value::Int(1));
            assert!(node.tail.is_some());
            // Verify second element
            let second = node.tail.as_ref().unwrap();
            assert_eq!(second.head, Value::Int(2));
        }
        _ => panic!("Expected list, got {:?}", result),
    }
}

#[test]
fn test_cons_operation() {
    let result = run("1 :: []").unwrap();
    match result {
        Value::List(Some(node)) => {
            assert_eq!(node.head, Value::Int(1));
            assert!(node.tail.is_none());
        }
        _ => panic!("Expected list, got {:?}", result),
    }
}

#[test]
fn test_cons_with_list() {
    let result = run("1 :: [2; 3]").unwrap();
    match result {
        Value::List(Some(node)) => {
            assert_eq!(node.head, Value::Int(1));
            let tail = node.tail.as_ref().unwrap();
            assert_eq!(tail.head, Value::Int(2));
        }
        _ => panic!("Expected list, got {:?}", result),
    }
}

#[test]
fn test_nested_cons() {
    let result = run("1 :: 2 :: 3 :: []").unwrap();
    match result {
        Value::List(Some(node)) => {
            assert_eq!(node.head, Value::Int(1));
            assert!(node.tail.is_some());
        }
        _ => panic!("Expected list, got {:?}", result),
    }
}

#[test]
fn test_list_in_let_binding() {
    let result = run("let nums = [1; 2; 3] in nums").unwrap();
    assert!(matches!(result, Value::List(Some(_))));
}

#[test]
fn test_empty_list_in_let() {
    let result = run("let empty = [] in empty").unwrap();
    assert!(matches!(result, Value::List(None)));
}

#[test]
fn test_cons_in_let() {
    let result = run("let list = 1 :: [2; 3] in list").unwrap();
    assert!(matches!(result, Value::List(Some(_))));
}

#[test]
fn test_list_with_variables() {
    let result = run("let x = 1 in let y = 2 in [x; y]").unwrap();
    match result {
        Value::List(Some(node)) => {
            assert_eq!(node.head, Value::Int(1));
            let tail = node.tail.as_ref().unwrap();
            assert_eq!(tail.head, Value::Int(2));
        }
        _ => panic!("Expected list, got {:?}", result),
    }
}

#[test]
fn test_list_with_expressions() {
    let result = run("[1 + 1; 2 * 2]").unwrap();
    match result {
        Value::List(Some(node)) => {
            assert_eq!(node.head, Value::Int(2));
            let tail = node.tail.as_ref().unwrap();
            assert_eq!(tail.head, Value::Int(4));
        }
        _ => panic!("Expected list, got {:?}", result),
    }
}

#[test]
fn test_cons_with_expression() {
    let result = run("(1 + 1) :: [3]").unwrap();
    match result {
        Value::List(Some(node)) => {
            assert_eq!(node.head, Value::Int(2));
        }
        _ => panic!("Expected list, got {:?}", result),
    }
}

#[test]
fn test_list_equality() {
    let result = run("[1; 2] = [1; 2]").unwrap();
    assert_eq!(result, Value::Bool(true));
}

#[test]
fn test_list_inequality() {
    let result = run("[1] <> [2]").unwrap();
    assert_eq!(result, Value::Bool(true));
}

#[test]
fn test_empty_list_equality() {
    let result = run("[] = []").unwrap();
    assert_eq!(result, Value::Bool(true));
}

// Future: Pattern matching tests (will be implemented later)
#[test]
#[ignore]
fn test_list_pattern_match_empty() {
    // match [] with | [] -> true | _ -> false
    let result = run("let list = [] in if list = [] then true else false").unwrap();
    assert_eq!(result, Value::Bool(true));
}

#[test]
#[ignore]
fn test_list_pattern_match_cons() {
    // match [1;2] with | h :: t -> h | [] -> 0
    // This requires pattern matching syntax which is a future enhancement
}
