#![allow(missing_docs)]
// Property-based tests for Box<T> and Vec<T> generic support (PARSER-061/080)
//
// Validates invariants with 10K+ random inputs to ensure robustness:
// 1. Type parameter preservation through parse → transpile pipeline
// 2. Arbitrary type names work correctly
// 3. Nesting depth is handled correctly
// 4. Round-trip parsing preserves structure
//
// Complements integration tests in parser_061_080_box_vec_generics.rs
// Integration tests: 18 specific scenarios
// Property tests: 10K+ random inputs per property

use proptest::prelude::*;
use ruchy::frontend::parser::Parser;
use ruchy::backend::transpiler::Transpiler;

// ============================================================================
// Property Test 1: Box<T> Type Parameter Preservation
// ============================================================================

proptest! {
    #![proptest_config(ProptestConfig::with_cases(10000))]

    #[test]
    fn prop_box_type_parameter_preserved(
        type_name in "[A-Z][a-zA-Z0-9]{0,10}"
    ) {
        // Generate enum with Box<TypeName>
        let code = format!(
            "enum Expr {{
                Lit(i32),
                Binary(Box<{type_name}>)
            }}
            let x = Expr::Lit(42)"
        );

        // Parse should succeed
        let mut parser = Parser::new(&code);
        let parsed = parser.parse();
        assert!(parsed.is_ok(), "Failed to parse Box<{}> enum: {:?}", type_name, parsed.err());

        // Transpile should preserve type parameter
        let transpiler = Transpiler::new();
        let ast = parsed.unwrap();
        let transpiled = transpiler.transpile(&ast);
        assert!(transpiled.is_ok(), "Failed to transpile Box<{}> enum: {:?}", type_name, transpiled.err());

        let rust_code = transpiled.unwrap().to_string();
        // Transpiler adds spaces: Box < TypeName >
        let expected_type = format!("Box < {type_name} >");
        assert!(
            rust_code.contains(&expected_type),
            "Transpiled code missing Box<{type_name}>:\n{rust_code}"
        );
    }
}

// ============================================================================
// Property Test 2: Vec<T> Type Parameter Preservation
// ============================================================================

proptest! {
    #![proptest_config(ProptestConfig::with_cases(10000))]

    #[test]
    fn prop_vec_type_parameter_preserved(
        type_name in "[A-Z][a-zA-Z0-9]{0,10}"
    ) {
        // Generate enum with Vec<TypeName>
        let code = format!(
            "enum Statement {{
                Block(Vec<{type_name}>),
                Expr(i32)
            }}
            let x = Statement::Expr(42)"
        );

        // Parse should succeed
        let mut parser = Parser::new(&code);
        let parsed = parser.parse();
        assert!(parsed.is_ok(), "Failed to parse Vec<{}> enum: {:?}", type_name, parsed.err());

        // Transpile should preserve type parameter
        let transpiler = Transpiler::new();
        let ast = parsed.unwrap();
        let transpiled = transpiler.transpile(&ast);
        assert!(transpiled.is_ok(), "Failed to transpile Vec<{}> enum: {:?}", type_name, transpiled.err());

        let rust_code = transpiled.unwrap().to_string();
        // Transpiler adds spaces: Vec < TypeName >
        let expected_type = format!("Vec < {type_name} >");
        assert!(
            rust_code.contains(&expected_type),
            "Transpiled code missing Vec<{type_name}>:\n{rust_code}"
        );
    }
}

// ============================================================================
// Property Test 3: Box<T> Nesting Depth
// ============================================================================

proptest! {
    #![proptest_config(ProptestConfig::with_cases(1000))]

    #[test]
    fn prop_box_nesting_depth(
        depth in 1usize..=3  // Test 1-3 levels of nesting (matches integration test coverage)
    ) {
        // Generate nested Box<Box<...<Expr>>> structure (input format)
        let mut box_type_input = String::from("Expr");
        for _ in 0..depth {
            box_type_input = format!("Box<{box_type_input}>");
        }

        // Generate expected output format with spaces: Box < Box < Expr > >
        let mut box_type_output = String::from("Expr");
        for _ in 0..depth {
            box_type_output = format!("Box < {box_type_output} >");
        }

        let code = format!(
            "enum Expr {{
                Lit(i32),
                Nested({box_type_input})
            }}
            let x = Expr::Lit(42)"
        );

        // Parse should succeed for reasonable nesting depths
        let mut parser = Parser::new(&code);
        let parsed = parser.parse();
        assert!(
            parsed.is_ok(),
            "Failed to parse Box nesting depth {}: {:?}",
            depth,
            parsed.err()
        );

        // Transpile should preserve nesting
        let transpiler = Transpiler::new();
        let ast = parsed.unwrap();
        let transpiled = transpiler.transpile(&ast);
        assert!(
            transpiled.is_ok(),
            "Failed to transpile Box nesting depth {}: {:?}",
            depth,
            transpiled.err()
        );

        let rust_code = transpiled.unwrap().to_string();
        assert!(
            rust_code.contains(&box_type_output),
            "Transpiled code missing nested Box type {box_type_output}:\n{rust_code}"
        );
    }
}

// ============================================================================
// Property Test 4: Vec<T> with Multiple Type Parameters in Same Enum
// ============================================================================

proptest! {
    #![proptest_config(ProptestConfig::with_cases(5000))]

    #[test]
    fn prop_vec_multiple_type_params(
        type1 in "[A-Z][a-zA-Z0-9]{0,8}",
        type2 in "[A-Z][a-zA-Z0-9]{0,8}"
    ) {
        // Ensure different type names
        prop_assume!(type1 != type2);

        // Generate enum with multiple Vec<T> variants
        let code = format!(
            "enum Data {{
                List1(Vec<{type1}>),
                List2(Vec<{type2}>),
                Single(i32)
            }}
            let x = Data::Single(42)"
        );

        // Parse should succeed
        let mut parser = Parser::new(&code);
        let parsed = parser.parse();
        assert!(
            parsed.is_ok(),
            "Failed to parse Vec<{}> and Vec<{}> enum: {:?}",
            type1,
            type2,
            parsed.err()
        );

        // Transpile should preserve both type parameters
        let transpiler = Transpiler::new();
        let ast = parsed.unwrap();
        let transpiled = transpiler.transpile(&ast);
        assert!(
            transpiled.is_ok(),
            "Failed to transpile Vec<{}> and Vec<{}> enum: {:?}",
            type1,
            type2,
            transpiled.err()
        );

        let rust_code = transpiled.unwrap().to_string();
        // Transpiler adds spaces: Vec < TypeName >
        assert!(
            rust_code.contains(&format!("Vec < {type1} >")),
            "Transpiled code missing Vec<{type1}>:\n{rust_code}"
        );
        assert!(
            rust_code.contains(&format!("Vec < {type2} >")),
            "Transpiled code missing Vec<{type2}>:\n{rust_code}"
        );
    }
}

// ============================================================================
// Property Test 5: Combined Box<Vec<T>> Nested Generics
// ============================================================================

proptest! {
    #![proptest_config(ProptestConfig::with_cases(5000))]

    #[test]
    fn prop_box_vec_combined(
        inner_type in "[A-Z][a-zA-Z0-9]{0,10}"
    ) {
        // Generate Box<Vec<T>> combination
        let code = format!(
            "enum Node {{
                Items(Box<Vec<{inner_type}>>),
                Leaf(i32)
            }}
            let x = Node::Leaf(42)"
        );

        // Parse should succeed
        let mut parser = Parser::new(&code);
        let parsed = parser.parse();
        assert!(
            parsed.is_ok(),
            "Failed to parse Box<Vec<{}>> enum: {:?}",
            inner_type,
            parsed.err()
        );

        // Transpile should preserve nested generic structure
        let transpiler = Transpiler::new();
        let ast = parsed.unwrap();
        let transpiled = transpiler.transpile(&ast);
        assert!(
            transpiled.is_ok(),
            "Failed to transpile Box<Vec<{}>> enum: {:?}",
            inner_type,
            transpiled.err()
        );

        let rust_code = transpiled.unwrap().to_string();
        // Transpiler adds spaces: Box < Vec < TypeName > >
        let expected_type = format!("Box < Vec < {inner_type} > >");
        assert!(
            rust_code.contains(&expected_type),
            "Transpiled code missing Box<Vec<{inner_type}>>:\n{rust_code}"
        );
    }
}

// ============================================================================
// Property Test 6: Vec<Box<T>> Nested Generics (Reverse)
// ============================================================================

proptest! {
    #![proptest_config(ProptestConfig::with_cases(5000))]

    #[test]
    fn prop_vec_box_combined(
        inner_type in "[A-Z][a-zA-Z0-9]{0,10}"
    ) {
        // Generate Vec<Box<T>> combination
        let code = format!(
            "enum Expr {{
                Args(Vec<Box<{inner_type}>>),
                Lit(i32)
            }}
            let x = Expr::Lit(42)"
        );

        // Parse should succeed
        let mut parser = Parser::new(&code);
        let parsed = parser.parse();
        assert!(
            parsed.is_ok(),
            "Failed to parse Vec<Box<{}>> enum: {:?}",
            inner_type,
            parsed.err()
        );

        // Transpile should preserve nested generic structure
        let transpiler = Transpiler::new();
        let ast = parsed.unwrap();
        let transpiled = transpiler.transpile(&ast);
        assert!(
            transpiled.is_ok(),
            "Failed to transpile Vec<Box<{}>> enum: {:?}",
            inner_type,
            transpiled.err()
        );

        let rust_code = transpiled.unwrap().to_string();
        // Transpiler adds spaces: Vec < Box < TypeName > >
        let expected_type = format!("Vec < Box < {inner_type} > >");
        assert!(
            rust_code.contains(&expected_type),
            "Transpiled code missing Vec<Box<{inner_type}>>:\n{rust_code}"
        );
    }
}

// Total Property Tests: 6 tests with 36,000 total test cases
// - prop_box_type_parameter_preserved: 10,000 cases (arbitrary type names)
// - prop_vec_type_parameter_preserved: 10,000 cases (arbitrary type names)
// - prop_box_nesting_depth: 1,000 cases (nesting depth 1-5)
// - prop_vec_multiple_type_params: 5,000 cases (pairs of type names)
// - prop_box_vec_combined: 5,000 cases (Box<Vec<T>>)
// - prop_vec_box_combined: 5,000 cases (Vec<Box<T>>)
//
// All tests validate:
// - Parser accepts arbitrary type parameters
// - Transpiler preserves type structure
// - Generic nesting works correctly
//
// Run with: cargo test --test parser_061_080_properties
