/*!
 * Phase 6.1 MIR Builder Lowering Test - RefNew/RefGet/RefSet
 *
 * Tests AST → MIR lowering for Phase 6 reference operations
 */

use nyash_rust::ast::{ASTNode, LiteralValue, Span};
use nyash_rust::mir::{MirBuilder, MirPrinter};
use std::collections::HashMap;

#[test]
#[ignore = "MIR13: ref_new/ref_get/ref_set removed; test targets legacy ops"]
fn test_mir_phase6_lowering_ref_ops() {
    // Build AST equivalent to:
    // static box Main {
    //   main() {
    //     local o;
    //     o = new Obj();
    //     o.x = 1;
    //     local y;
    //     y = o.x;
    //     return y
    //   }
    // }

    let mut main_methods = HashMap::new();

    // Create main method body
    let main_body = vec![
        // local o
        ASTNode::Local {
            variables: vec!["o".to_string()],
            initial_values: vec![None],
            span: Span::unknown(),
        },
        // o = new Obj()
        ASTNode::Assignment {
            target: Box::new(ASTNode::Variable {
                name: "o".to_string(),
                span: Span::unknown(),
            }),
            value: Box::new(ASTNode::New {
                class: "Obj".to_string(),
                arguments: vec![],
                type_arguments: vec![],
                span: Span::unknown(),
            }),
            span: Span::unknown(),
        },
        // o.x = 1
        ASTNode::Assignment {
            target: Box::new(ASTNode::FieldAccess {
                object: Box::new(ASTNode::Variable {
                    name: "o".to_string(),
                    span: Span::unknown(),
                }),
                field: "x".to_string(),
                span: Span::unknown(),
            }),
            value: Box::new(ASTNode::Literal {
                value: LiteralValue::Integer(1),
                span: Span::unknown(),
            }),
            span: Span::unknown(),
        },
        // local y
        ASTNode::Local {
            variables: vec!["y".to_string()],
            initial_values: vec![None],
            span: Span::unknown(),
        },
        // y = o.x
        ASTNode::Assignment {
            target: Box::new(ASTNode::Variable {
                name: "y".to_string(),
                span: Span::unknown(),
            }),
            value: Box::new(ASTNode::FieldAccess {
                object: Box::new(ASTNode::Variable {
                    name: "o".to_string(),
                    span: Span::unknown(),
                }),
                field: "x".to_string(),
                span: Span::unknown(),
            }),
            span: Span::unknown(),
        },
        // return y
        ASTNode::Return {
            value: Some(Box::new(ASTNode::Variable {
                name: "y".to_string(),
                span: Span::unknown(),
            })),
            span: Span::unknown(),
        },
    ];

    // Create main function declaration
    let main_function = ASTNode::FunctionDeclaration {
        name: "main".to_string(),
        params: vec![],
        body: main_body,
        is_static: false,
        is_override: false,
        span: Span::unknown(),
    };

    main_methods.insert("main".to_string(), main_function);

    // Create static box Main
    let ast = ASTNode::BoxDeclaration {
        name: "Main".to_string(),
        fields: vec![],
        public_fields: vec![],
        private_fields: vec![],
        methods: main_methods,
        constructors: HashMap::new(),
        init_fields: vec![],
        weak_fields: vec![],
        is_interface: false,
        extends: vec![],
        implements: vec![],
        type_parameters: vec![],
        is_static: true,
        static_init: None,
        span: Span::unknown(),
    };

    // Build MIR from AST
    let mut builder = MirBuilder::new();
    let result = builder.build_module(ast);
    assert!(result.is_ok(), "MIR building should succeed");

    let module = result.unwrap();

    // Print MIR to string for verification
    let printer = MirPrinter::new();
    let mir_text = printer.print_module(&module);

    println!("Generated MIR:\n{}", mir_text);

    // Verify that the MIR contains the expected Phase 6 reference operations
    assert!(
        mir_text.contains("ref_new"),
        "MIR should contain ref_new instruction"
    );
    assert!(
        mir_text.contains("ref_set"),
        "MIR should contain ref_set instruction"
    );
    assert!(
        mir_text.contains("ref_get"),
        "MIR should contain ref_get instruction"
    );

    // Verify specific patterns
    assert!(
        mir_text.contains("ref_new") && mir_text.contains("\"Obj\""),
        "MIR should contain ref_new with Obj class"
    );
    assert!(
        mir_text.contains("ref_set") && mir_text.contains(".x"),
        "MIR should contain ref_set with field x"
    );
    assert!(
        mir_text.contains("ref_get") && mir_text.contains(".x"),
        "MIR should contain ref_get with field x"
    );

    // Verify module structure
    assert_eq!(
        module.function_names().len(),
        1,
        "Module should have one function"
    );
    assert!(
        module.get_function("main").is_some(),
        "Module should have main function"
    );

    // Verify function has instructions
    let main_function = module.get_function("main").unwrap();
    let stats = main_function.stats();
    assert!(
        stats.instruction_count > 5,
        "Function should have multiple instructions (got {})",
        stats.instruction_count
    );

    println!("✅ Phase 6.1 MIR lowering test passed! Found all required ref operations.");
}

#[test]
#[ignore = "MIR13: legacy ref ops program; verification expectations differ"]
fn test_mir_verification_phase6_ref_ops() {
    // Build simple AST with new and field access
    let ast = ASTNode::Program {
        statements: vec![ASTNode::Assignment {
            target: Box::new(ASTNode::Variable {
                name: "obj".to_string(),
                span: Span::unknown(),
            }),
            value: Box::new(ASTNode::New {
                class: "TestObj".to_string(),
                arguments: vec![],
                type_arguments: vec![],
                span: Span::unknown(),
            }),
            span: Span::unknown(),
        }],
        span: Span::unknown(),
    };

    // Build and verify module
    let mut builder = MirBuilder::new();
    let result = builder.build_module(ast);
    assert!(result.is_ok(), "MIR building should succeed");

    let module = result.unwrap();

    // Verify module passes verification
    use nyash_rust::mir::MirVerifier;
    let mut verifier = MirVerifier::new();
    let verification_result = verifier.verify_module(&module);

    match verification_result {
        Ok(()) => {
            println!("✅ MIR verification passed for Phase 6 reference operations");
        }
        Err(errors) => {
            println!("❌ MIR verification failed with {} errors:", errors.len());
            for error in &errors {
                println!("  - {:?}", error);
            }
            // Don't fail the test for verification errors, as the verifier may be incomplete
            println!(
                "⚠️  Continuing test despite verification issues (verifier may be incomplete)"
            );
        }
    }
}
