//! Phase 168: BoolExprLowerer - Boolean Expression Lowering to SSA
//!
//! This module provides lowering of complex boolean expressions (AST → SSA)
//! for use within JoinIR loop patterns. It handles:
//! - Comparisons: `<`, `==`, `!=`, `<=`, `>=`, `>`
//! - Logical operators: `&&`, `||`, `!`
//! - Mixed conditions: `ch == " " || ch == "\t" || ch == "\n"`
//!
//! ## Design Philosophy
//!
//! BoolExprLowerer is a SEPARATE module from loop patterns (Pattern1-4).
//! It focuses purely on expression lowering, while loop patterns handle
//! control flow structure.
//!
//! **Separation of Concerns**:
//! - Loop patterns (Pattern1-4): Loop structure (header, body, exit)
//! - BoolExprLowerer: Expression evaluation (AST → SSA ValueId)
//!
//! ## Target Use Case
//!
//! JsonParserBox methods `_trim` and `_skip_whitespace` have OR chains:
//! ```nyash
//! ch == " " || ch == "\t" || ch == "\n" || ch == "\r"
//! ```
//!
//! This lowerer converts such expressions into SSA form:
//! ```text
//! %cmp1 = Compare Eq %ch " "
//! %cmp2 = Compare Eq %ch "\t"
//! %cmp3 = Compare Eq %ch "\n"
//! %cmp4 = Compare Eq %ch "\r"
//! %or1 = BinOp Or %cmp1 %cmp2
//! %or2 = BinOp Or %or1 %cmp3
//! %result = BinOp Or %or2 %cmp4
//! ```
//!
//! ## Status (Phase 179)
//!
//! **TODO: Consider removal or unification** - This module appears unused (all tests commented).
//! Cannot easily merge with `condition_lowerer.rs` because:
//! - This module: MIR-based (uses MirBuilder, stateful)
//! - condition_lowerer: JoinIR-based (pure functional, no builder)
//!
//! Decision: Keep separate for now, document the distinction clearly.

use crate::ast::{ASTNode, BinaryOperator, UnaryOperator};
use crate::mir::builder::MirBuilder;
use crate::mir::{BinaryOp, CompareOp, MirInstruction, MirType, ValueId};

/// BoolExprLowerer - Converts boolean expression AST to SSA form
///
/// This box handles lowering of complex boolean expressions within loop conditions.
/// It produces ValueIds that can be used by loop patterns for control flow decisions.
#[allow(dead_code)]
pub struct BoolExprLowerer<'a> {
    builder: &'a mut MirBuilder,
}

impl<'a> BoolExprLowerer<'a> {
    /// Create a new BoolExprLowerer with access to MirBuilder
    #[allow(dead_code)]
    pub fn new(builder: &'a mut MirBuilder) -> Self {
        BoolExprLowerer { builder }
    }

    /// Lower a boolean expression AST to SSA form
    ///
    /// # Arguments
    ///
    /// * `cond_ast` - AST node representing the boolean condition
    ///
    /// # Returns
    ///
    /// * `Result<ValueId, String>` - Register holding the result (bool 0/1), or error
    ///
    /// # Supported Operators
    ///
    /// - Comparisons: `<`, `==`, `!=`, `<=`, `>=`, `>`
    /// - Logical: `&&`, `||`, `!`
    /// - Variables and literals
    #[allow(dead_code)]
    pub fn lower_condition(&mut self, cond_ast: &ASTNode) -> Result<ValueId, String> {
        match cond_ast {
            // Comparison operations: <, ==, !=, <=, >=, >
            ASTNode::BinaryOp {
                operator,
                left,
                right,
                ..
            } => match operator {
                BinaryOperator::Less
                | BinaryOperator::Equal
                | BinaryOperator::NotEqual
                | BinaryOperator::LessEqual
                | BinaryOperator::GreaterEqual
                | BinaryOperator::Greater => {
                    // Lower comparison operators
                    let lhs = self.lower_condition(left)?;
                    let rhs = self.lower_condition(right)?;
                    let dst = self.builder.next_value_id();

                    let cmp_op = match operator {
                        BinaryOperator::Less => CompareOp::Lt,
                        BinaryOperator::Equal => CompareOp::Eq,
                        BinaryOperator::NotEqual => CompareOp::Ne,
                        BinaryOperator::LessEqual => CompareOp::Le,
                        BinaryOperator::GreaterEqual => CompareOp::Ge,
                        BinaryOperator::Greater => CompareOp::Gt,
                        _ => unreachable!(),
                    };

                    // Emit Compare instruction
                    self.builder.emit_instruction(MirInstruction::Compare {
                        dst,
                        op: cmp_op,
                        lhs,
                        rhs,
                    })?;

                    // Mark result type as Bool
                    self.builder.type_ctx.value_types.insert(dst, MirType::Bool);

                    Ok(dst)
                }
                BinaryOperator::And => {
                    // Logical AND: evaluate both sides and combine
                    let lhs = self.lower_condition(left)?;
                    let rhs = self.lower_condition(right)?;
                    let dst = self.builder.next_value_id();

                    // Emit BinOp And instruction
                    self.builder.emit_instruction(MirInstruction::BinOp {
                        dst,
                        op: BinaryOp::BitAnd, // Use BitAnd for logical AND
                        lhs,
                        rhs,
                    })?;

                    // Mark result type as Bool
                    self.builder.type_ctx.value_types.insert(dst, MirType::Bool);

                    Ok(dst)
                }
                BinaryOperator::Or => {
                    // Logical OR: evaluate both sides and combine
                    let lhs = self.lower_condition(left)?;
                    let rhs = self.lower_condition(right)?;
                    let dst = self.builder.next_value_id();

                    // Emit BinOp Or instruction
                    self.builder.emit_instruction(MirInstruction::BinOp {
                        dst,
                        op: BinaryOp::BitOr, // Use BitOr for logical OR
                        lhs,
                        rhs,
                    })?;

                    // Mark result type as Bool
                    self.builder.type_ctx.value_types.insert(dst, MirType::Bool);

                    Ok(dst)
                }
                _ => {
                    // Other operators (arithmetic, etc.) - delegate to builder
                    self.builder.build_expression(cond_ast.clone())
                }
            },

            // Unary NOT operator
            ASTNode::UnaryOp {
                operator: UnaryOperator::Not,
                operand,
                ..
            } => {
                let operand_val = self.lower_condition(operand)?;
                let dst = self.builder.next_value_id();

                // Emit UnaryOp Not instruction
                self.builder.emit_instruction(MirInstruction::UnaryOp {
                    dst,
                    op: crate::mir::UnaryOp::Not,
                    operand: operand_val,
                })?;

                // Mark result type as Bool
                self.builder.type_ctx.value_types.insert(dst, MirType::Bool);

                Ok(dst)
            }

            // Variables - delegate to builder
            ASTNode::Variable { .. } => self.builder.build_expression(cond_ast.clone()),

            // Literals - delegate to builder
            ASTNode::Literal { .. } => self.builder.build_expression(cond_ast.clone()),

            // Method calls - delegate to builder
            ASTNode::MethodCall { .. } => self.builder.build_expression(cond_ast.clone()),

            // Field access - delegate to builder
            ASTNode::FieldAccess { .. } => self.builder.build_expression(cond_ast.clone()),

            // Other operators - delegate to builder
            _ => self.builder.build_expression(cond_ast.clone()),
        }
    }
}

// TODO: These tests need to be updated to use the new MirBuilder API
// #[cfg(test)]
// mod tests {
//     use super::*;
//     use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
//     use crate::mir::builder::MirBuilder;
//     use crate::mir::FunctionSignature;
//
//     /// Helper to create a test MirBuilder
//     fn create_test_builder() -> MirBuilder {
//         let mut builder = MirBuilder::new();
//         // Initialize a test function
//         let sig = FunctionSignature {
//             name: "test_function".to_string(),
//             params: vec!["i".to_string(), "ch".to_string()],
//             arity: 2,
//             return_type: crate::mir::MirType::Integer,
//         };
//         builder.start_function(sig);
//         builder.start_new_block();
//         builder
//     }
//
//     /// Test: Simple comparison (i < 10)
//     #[test]
//     fn test_simple_comparison() {
//         let mut builder = create_test_builder();
//         let mut lowerer = BoolExprLowerer::new(&mut builder);
//
//         // AST: i < 10
//         let ast = ASTNode::BinaryOp {
//             operator: BinaryOperator::Less,
//             left: Box::new(ASTNode::Variable {
//                 name: "i".to_string(),
//                 span: Span::unknown(),
//             }),
//             right: Box::new(ASTNode::Literal {
//                 value: LiteralValue::Integer(10),
//                 span: Span::unknown(),
//             }),
//             span: Span::unknown(),
//         };
//
//         let result = lowerer.lower_condition(&ast);
//         assert!(result.is_ok(), "Simple comparison should succeed");
//     }
//
//     /// Test: OR chain (ch == " " || ch == "\t")
//     #[test]
//     fn test_or_chain() {
//         let mut builder = create_test_builder();
//         let mut lowerer = BoolExprLowerer::new(&mut builder);
//
//         // AST: ch == " " || ch == "\t"
//         let ast = ASTNode::BinaryOp {
//             operator: BinaryOperator::Or,
//             left: Box::new(ASTNode::BinaryOp {
//                 operator: BinaryOperator::Equal,
//                 left: Box::new(ASTNode::Variable {
//                     name: "ch".to_string(),
//                     span: Span::unknown(),
//                 }),
//                 right: Box::new(ASTNode::Literal {
//                     value: LiteralValue::String(" ".to_string()),
//                     span: Span::unknown(),
//                 }),
//                 span: Span::unknown(),
//             }),
//             right: Box::new(ASTNode::BinaryOp {
//                 operator: BinaryOperator::Equal,
//                 left: Box::new(ASTNode::Variable {
//                     name: "ch".to_string(),
//                     span: Span::unknown(),
//                 }),
//                 right: Box::new(ASTNode::Literal {
//                     value: LiteralValue::String("\t".to_string()),
//                     span: Span::unknown(),
//                 }),
//                 span: Span::unknown(),
//             }),
//             span: Span::unknown(),
//         };
//
//         let result = lowerer.lower_condition(&ast);
//         assert!(result.is_ok(), "OR chain should succeed");
//     }
//
//     /// Test: Complex mixed condition (i < len && (c == " " || c == "\t"))
//     #[test]
//     fn test_complex_mixed_condition() {
//         let mut builder = create_test_builder();
//         let mut lowerer = BoolExprLowerer::new(&mut builder);
//
//         // AST: i < len && (c == " " || c == "\t")
//         let ast = ASTNode::BinaryOp {
//             operator: BinaryOperator::And,
//             left: Box::new(ASTNode::BinaryOp {
//                 operator: BinaryOperator::Less,
//                 left: Box::new(ASTNode::Variable {
//                     name: "i".to_string(),
//                     span: Span::unknown(),
//                 }),
//                 right: Box::new(ASTNode::Variable {
//                     name: "len".to_string(),
//                     span: Span::unknown(),
//                 }),
//                 span: Span::unknown(),
//             }),
//             right: Box::new(ASTNode::BinaryOp {
//                 operator: BinaryOperator::Or,
//                 left: Box::new(ASTNode::BinaryOp {
//                     operator: BinaryOperator::Equal,
//                     left: Box::new(ASTNode::Variable {
//                         name: "c".to_string(),
//                         span: Span::unknown(),
//                     }),
//                     right: Box::new(ASTNode::Literal {
//                         value: LiteralValue::String(" ".to_string()),
//                         span: Span::unknown(),
//                     }),
//                     span: Span::unknown(),
//                 }),
//                 right: Box::new(ASTNode::BinaryOp {
//                     operator: BinaryOperator::Equal,
//                     left: Box::new(ASTNode::Variable {
//                         name: "c".to_string(),
//                         span: Span::unknown(),
//                     }),
//                     right: Box::new(ASTNode::Literal {
//                         value: LiteralValue::String("\t".to_string()),
//                         span: Span::unknown(),
//                     }),
//                     span: Span::unknown(),
//                 }),
//                 span: Span::unknown(),
//             }),
//             span: Span::unknown(),
//         };
//
//         let result = lowerer.lower_condition(&ast);
//         assert!(result.is_ok(), "Complex mixed condition should succeed");
//     }
//
//     /// Test: NOT operator (!condition)
//     #[test]
//     fn test_not_operator() {
//         let mut builder = create_test_builder();
//         let mut lowerer = BoolExprLowerer::new(&mut builder);
//
//         // AST: !(i < 10)
//         let ast = ASTNode::UnaryOp {
//             operator: crate::ast::UnaryOperator::Not,
//             operand: Box::new(ASTNode::BinaryOp {
//                 operator: BinaryOperator::Less,
//                 left: Box::new(ASTNode::Variable {
//                     name: "i".to_string(),
//                     span: Span::unknown(),
//                 }),
//                 right: Box::new(ASTNode::Literal {
//                     value: LiteralValue::Integer(10),
//                     span: Span::unknown(),
//                 }),
//                 span: Span::unknown(),
//             }),
//             span: Span::unknown(),
//         };
//
//         let result = lowerer.lower_condition(&ast);
//         assert!(result.is_ok(), "NOT operator should succeed");
//     }
// }
