use super::*;

#[cfg(test)]
fn fun_grammar() -> Grammar {
    load_example_grammar("fun")
}

pub fn valid_expressions_cases() -> Vec<ParseTestCase> {
    let cases = vec![
        // === Literals ===
        ParseTestCase::valid("integer literal", "42"),
        ParseTestCase::valid("zero", "0"),
        ParseTestCase::valid("float literal", "3.14"),
        ParseTestCase::valid("boolean true", "true"),
        ParseTestCase::valid("boolean false", "false"),
        // === Arithmetic ===
        ParseTestCase::valid("int addition", "1 + 2"),
        ParseTestCase::valid("int multiplication", "3 * 4"),
        ParseTestCase::valid("float addition", "1.0 +. 2.5"),
        ParseTestCase::valid("float division", "10.0 /. 2.0"),
        ParseTestCase::valid("float op with completable int", "1.0 +. 2"),
        // === Lambda ===
        ParseTestCase::valid("simple lambda", "(x: Int) => x + 1"),
        ParseTestCase::valid("float lambda", "(x: Float) => x *. 2.0"),
        // === Application ===
        ParseTestCase::valid("lambda application", "((x: Int) => x + 1)(41)"),
        // === Let binding ===
        ParseTestCase::valid("simple let", "let n: Int = 12; n + 1"),
        // === Expanded: many more valid cases (variations, nesting, combos) ===
        // Literal variants
        ParseTestCase::valid("int 1", "1"),
        ParseTestCase::valid("int 2", "2"),
        ParseTestCase::valid("int 3", "3"),
        ParseTestCase::valid("int 10", "10"),
        ParseTestCase::valid("large int", "1000"),
        ParseTestCase::valid("float 1", "0.5"),
        ParseTestCase::valid("float 2", "2.0"),
        ParseTestCase::valid("float 3", "123.456"),
        ParseTestCase::valid("true literal", "true"),
        ParseTestCase::valid("false literal", "false"),
        // More arithmetic shapes
        ParseTestCase::valid("sum chain 3", "1 + 2 + 3"),
        ParseTestCase::valid("sum chain 4", "1 + 2 + 3 + 4"),
        ParseTestCase::valid("mult and add", "1 + 2 * 3"),
        ParseTestCase::valid("paren precedence", "(1 + 2) * 3"),
        ParseTestCase::valid("nested parens", "((1 + 2) + 3) + 4"),
        ParseTestCase::valid("mixed float ops", "1.0 +. 2.0 +. 3.0"),
        ParseTestCase::valid("float-int mix with op", "1.0 +. 2"),
        // Parentheses and grouping
        ParseTestCase::valid("single paren", "(1)"),
        ParseTestCase::valid("double paren", "((1))"),
        ParseTestCase::valid("paren around binop", "(1 + 2)"),
        ParseTestCase::valid("deep paren nesting", "((((1 + 2))))"),
        // More lambda shapes
        ParseTestCase::valid("identity lambda", "(x: Int) => x"),
        ParseTestCase::valid("lambda add one", "(x: Int) => x + 1"),
        ParseTestCase::valid("lambda multiply", "(x: Int) => x * 2"),
        ParseTestCase::valid("lambda float op", "(x: Float) => x +. 1.0"),
        ParseTestCase::valid("nested lambda simple", "(x: Int) => ((y: Int) => x + y)"),
        ParseTestCase::valid(
            "nested lambda applied",
            "((x: Int) => ((y: Int) => x + y))(1)(2)",
        ),
        // Repeated application patterns
        ParseTestCase::valid("apply literal lambda", "((x: Int) => x)(5)"),
        ParseTestCase::valid("apply expression lambda", "((x: Int) => x + 2)(3 + 4)"),
        ParseTestCase::valid("higher-order return lambda", "(f: Int -> Int) => f(1)"),
        // Let-binding variants
        ParseTestCase::valid("let then use", "let a: Int = 1; a"),
        ParseTestCase::valid("let chain 2", "let a: Int = 1; let b: Int = a + 2; b"),
        ParseTestCase::valid(
            "let with lambda",
            "let id: Int -> Int = (x: Int) => x; id(7)",
        ),
        ParseTestCase::valid("let float", "let f: Float = 2.5; f +. 1.5"),
        // Let + nested expressions
        ParseTestCase::valid("let nested expr", "let x: Int = (1 + 2) * 3; x + 4"),
        ParseTestCase::valid(
            "let lambda body",
            "let inc: Int -> Int = (x: Int) => x + 1; inc(9)",
        ),
        // Combined constructs
        ParseTestCase::valid(
            "let and nested lambda",
            "let mk: Int -> (Int -> Int) = (x: Int) => (y: Int) => x + y; mk(1)(2)",
        ),
        ParseTestCase::valid("lambda returning lambda", "(x: Int) => (y: Int) => x * y"),
        // Realistic small programs
        ParseTestCase::valid(
            "sum function application",
            "let sum: Int -> Int = (n: Int) => n + 0; sum(5)",
        ),
        ParseTestCase::valid(
            "compose simple",
            "let f: Int -> Int = (x: Int) => x + 1; let g: Int -> Int = (y: Int) => y * 2; g(f(3))",
        ),
        // Many small permutations of arithmetic and let usage
        ParseTestCase::valid(
            "perm 1",
            "let x: Int = 1; let y: Int = x + 2; let z: Int = y * 3; z",
        ),
        ParseTestCase::valid("perm 2", "let x: Int = 2; let y: Int = x * 4; y + 1"),
        ParseTestCase::valid("perm 3", "let x: Int = (1 + 1) * (2 + 2); x"),
        // Operator spacing variations (should still parse)
        ParseTestCase::valid("spacing a", "1+2"),
        ParseTestCase::valid("spacing b", "1 +2"),
        ParseTestCase::valid("spacing c", "1+ 2"),
        // More application / nesting depth cases
        ParseTestCase::valid("app depth 1", "((x: Int) => x + 1)(1)"),
        ParseTestCase::valid("app depth 2", "(((x: Int) => x + 1)(2))"),
        ParseTestCase::valid("app depth chain", "((x: Int) => (y: Int) => x + y)(1)(2)"),
        // Float-heavy expressions
        ParseTestCase::valid("float chain", "1.0 +. 2.0 +. 3.0 +. 4.0"),
        ParseTestCase::valid("float mixed paren", "(1.0 +. 2.0) *. 3.0"),
        // More let / lambda combos with context-like behavior
        ParseTestCase::valid(
            "let using let result",
            "let a: Int = 5; let b: Int = a + 3; let c: Int = b - 2; c",
        ),
        ParseTestCase::valid(
            "lambda capturing number literal",
            "(x: Int) => (y: Int) => x + (y + 1)",
        ),
        // Additional small programs to bulk up count
        ParseTestCase::valid(
            "prog 1",
            "let a: Int = 1; let b: Int = 2; (a + b) * (a + b)",
        ),
        ParseTestCase::valid("prog 2", "let x: Int = 10; let y: Int = x / 2; y"),
        ParseTestCase::valid("prog 3", "let f: Int -> Int = (n: Int) => n * n; f(4)"),
        // Additional trivial variations to reach ~10x density
        ParseTestCase::valid("trivial 1", "5"),
        ParseTestCase::valid("trivial 2", "6"),
        ParseTestCase::valid("trivial 3", "7"),
        ParseTestCase::valid("trivial 4", "8"),
        ParseTestCase::valid("trivial 5", "9"),
        ParseTestCase::valid("trivial 6", "11"),
        ParseTestCase::valid("trivial 7", "12"),
        ParseTestCase::valid("trivial 8", "13"),
        ParseTestCase::valid("trivial 9", "14"),
        ParseTestCase::valid("trivial 10", "15"),
        // Variations with parentheses and operators
        ParseTestCase::valid("paren mix 1", "(1 + (2 * 3))"),
        ParseTestCase::valid("paren mix 2", "((1 + 2) + (3 + 4))"),
        ParseTestCase::valid("complex expr 1", "(1 + 2) * (3 + 4) + 5"),
        ParseTestCase::valid("complex expr 2", "(1 + (2 + (3 + 4)))"),
        ParseTestCase::valid("complex expr 3", "((1 + 2) * (3 + 4)) / 2"),
    ];

    cases
}

pub fn invalid_expressions_cases() -> Vec<ParseTestCase> {
    vec![
        // === Syntax errors ===
        ParseTestCase::invalid("missing ':' in let", "let n Int = 12;"),
        ParseTestCase::invalid("missing semicolon", "let n: Int = 12 n"),
        ParseTestCase::invalid("bad identifier", "let 1x: Int = 3;"),
        ParseTestCase::invalid("close paren first", ")"),
        ParseTestCase::invalid("extra close paren", "(1))"),
        ParseTestCase::invalid("at sign", "@"),
        ParseTestCase::invalid("hash", "#"),
        ParseTestCase::invalid("dollar", "$x"),
        ParseTestCase::invalid("backslash", "\\x"),
        ParseTestCase::invalid("leading plus", "+ 1"),
        ParseTestCase::invalid("leading star", "* 2"),
        ParseTestCase::invalid("double operator", "1 ++ 2"),
        ParseTestCase::invalid("let no name", "let : Int = 1; 1"),
        ParseTestCase::invalid("let double semi", "let x: Int = 1;; x"),
        ParseTestCase::invalid("arrow without lambda", "=> 1"),
        ParseTestCase::invalid("lambda missing arrow", "(x: Int) x"),
        ParseTestCase::invalid("let missing rhs", "let x: Int = ; x"),
        ParseTestCase::invalid("app missing close paren", "f(1"),
        ParseTestCase::invalid("binary op missing rhs in parens", "(1 + )"),
        // === Type / validity errors ===
        ParseTestCase::invalid("int expected, float given", "let n: Int = 9.8; n"),
        ParseTestCase::invalid("float expected, int given", "let x: Float = 1; x"),
        ParseTestCase::invalid("let int declared bool value", "let x: Int = true; x"),
        ParseTestCase::invalid("let int declared float value", "let x: Int = 1.0; x"),
        // === Operator type errors ===
        ParseTestCase::invalid("int operator with float", "1 + 2.0"),
        ParseTestCase::invalid("mixed operators", "1 +. 2.0"),
        ParseTestCase::invalid("mixed operators", "3 +. 5"),
        ParseTestCase::invalid("bool plus int", "true + 1"),
        ParseTestCase::invalid("int plus bool", "1 + false"),
        ParseTestCase::invalid("bool float op", "true +. 1.0"),
        ParseTestCase::invalid("int with float op/.", "10 /. 2.0"),
        ParseTestCase::invalid(
            "closed int expr with float op",
            "((1 + 2) * (3 + 4)) /. 2.0",
        ),
        // === Application errors ===
        ParseTestCase::invalid("wrong argument type", "((x: Int) => x + 1)(2.0)"),
        ParseTestCase::invalid("apply non-function", "1(2)"),
        ParseTestCase::invalid("apply bool", "true(1)"),
        ParseTestCase::invalid("unbound x", "x"),
        ParseTestCase::invalid("unbound in expr", "x + 1"),
        ParseTestCase::invalid("unbound func", "f(1)"),
        ParseTestCase::invalid("unbound in let body", "let x: Int = 1; y"),
        ParseTestCase::invalid("var outside scope", "let x: Int = y; x"),
        ParseTestCase::invalid("bool let from int expr", "let b: Bool = 1 + 2; b"),
        ParseTestCase::invalid("lambda body uses missing var", "(x: Int) => y"),
        ParseTestCase::invalid("call returns bool used as int", "((x: Int) => true)(1) + 2"),
        ParseTestCase::invalid("wrong arg type bool for int", "f(true)")
            .with_context(vec![("f", "Int -> Int")]),
        ParseTestCase::invalid("wrong arg type int for bool", "f(1)")
            .with_context(vec![("f", "Bool -> Bool")]),
    ]
}

#[test]
fn valid_expressions_fun() {
    let mut grammar = fun_grammar();
    let cases = valid_expressions_cases();

    println!("\n=== Fun Valid Expressions ({} cases) ===", cases.len());

    let (res, _cases_json) = run_parse_batch(&mut grammar, &cases);

    assert_eq!(res.failed, 0, "{}", res.format_failures());

    println!(
        "✓ All {} cases passed in {:?} (avg {:?})",
        cases.len(),
        res.total_duration,
        res.avg_duration
    );
}

#[test]
fn invalid_expressions_fun() {
    let mut grammar = fun_grammar();
    let cases = invalid_expressions_cases();

    println!("\n=== Fun Invalid Expressions ({} cases) ===", cases.len());

    let (res, _cases_json) = run_parse_batch(&mut grammar, &cases);

    assert_eq!(res.failed, 0, "{}", res.format_failures());

    println!(
        "✓ All {} cases passed in {:?} (avg {:?})",
        res.passed, res.total_duration, res.avg_duration
    );
}

// Debug helper: inspect tokenization and parser result for specific failing prefixes
#[test]
#[ignore = "debug helper for investigating specific fun prefixes"]
fn debug_fun_failures() {
    let mut grammar = fun_grammar();
    crate::set_debug_level(crate::DebugLevel::Trace);
    let ctx = crate::logic::typing::Context::new();
    let cases = vec!["((x: Int) => x + 1)(", "(1 + 2) *", "(1.0 +. 2.0) *."];

    for s in cases {
        println!("\n--- Debug parse for: '{}' ---", s);
        match grammar.tokenize(s) {
            Ok(segs) => {
                println!("Segments ({}):", segs.len());
                for seg in segs.iter() {
                    println!("  '{}' @ {}", seg.as_str(), seg.index);
                }
            }
            Err(e) => println!("Tokenize error: {}", e),
        }

        let mut synth = crate::logic::synth::Synthesizer::new(grammar.clone(), s);
        match synth.parse_with(&ctx) {
            Ok(ast) => println!("Parsed OK: roots={}", ast.root_ids().len()),
            Err(e) => println!("Parse error: {}", e),
        }
    }
}
