//! Phase 134 P0: Suffix router box - unified with NormalizationPlanBox
//!
//! ## Responsibility
//!
//! - Detect block suffix starting with loop(true) { ... break } + post statements
//! - Delegate to NormalizationPlanBox for pattern detection (SSOT)
//! - Delegate to NormalizationExecuteBox for lowering and merge
//! - Return consumed count to skip processed statements in build_block()
//!
//! ## Contract
//!
//! - Returns Ok(Some(consumed)): Successfully processed remaining[..consumed]
//! - Returns Ok(None): Pattern not matched, use default behavior
//! - Returns Err(_): Internal error
//!
//! ## Design (Phase 134 P0)
//!
//! - Uses NormalizationPlanBox for detection (no duplication)
//! - Uses NormalizationExecuteBox for execution (shared logic)
//! - Only handles suffix-specific logic (return statement emission)

use crate::ast::ASTNode;
use crate::mir::builder::MirBuilder;
use crate::mir::builder::control_flow::normalization::{NormalizationPlanBox, NormalizationExecuteBox, PlanKind};

/// Box-First: Suffix router for normalized shadow lowering
pub struct NormalizedShadowSuffixRouterBox;

impl NormalizedShadowSuffixRouterBox {
    /// Try to lower a block suffix starting with loop(true) + post statements
    ///
    /// Phase 134 P0: Unified with NormalizationPlanBox for pattern detection
    ///
    /// Returns:
    /// - Ok(Some(consumed)): Successfully processed remaining[..consumed]
    /// - Ok(None): Pattern not matched, use default behavior
    /// - Err(_): Internal error
    pub fn try_lower_loop_suffix(
        builder: &mut MirBuilder,
        remaining: &[ASTNode],
        func_name: &str,
        debug: bool,
    ) -> Result<Option<usize>, String> {
        let trace = crate::mir::builder::control_flow::joinir::trace::trace();

        // Phase 134 P0: Delegate pattern detection to NormalizationPlanBox (SSOT)
        let plan = match NormalizationPlanBox::plan_block_suffix(builder, remaining, func_name, debug)? {
            Some(plan) => plan,
            None => {
                if debug {
                    trace.routing(
                        "suffix_router",
                        func_name,
                        "NormalizationPlanBox returned None (not a normalized pattern)",
                    );
                }
                return Ok(None);
            }
        };

        // Only handle suffix patterns (loop + post statements)
        // Loop-only patterns should go through try_normalized_shadow() instead
        match &plan.kind {
            PlanKind::LoopOnly => {
                if debug {
                    trace.routing(
                        "suffix_router",
                        func_name,
                        "Loop-only pattern detected, not a suffix (routing.rs should handle this)",
                    );
                }
                return Ok(None);
            }
            PlanKind::LoopWithPost { post_assign_count } => {
                if debug {
                    trace.routing(
                        "suffix_router",
                        func_name,
                        &format!(
                            "Loop+post pattern detected: {} post assigns",
                            post_assign_count
                        ),
                    );
                }
            }
        }

        // Phase 134 P0: Delegate execution to NormalizationExecuteBox (SSOT)
        match NormalizationExecuteBox::execute(builder, &plan, remaining, func_name, debug) {
            Ok(_value_id) => {
                // ExecuteBox returns a void constant, we don't need it for suffix routing
                // The consumed count is what build_block() needs
                if debug {
                    trace.routing(
                        "suffix_router",
                        func_name,
                        &format!("Normalization succeeded, consumed {} statements", plan.consumed),
                    );
                }
                Ok(Some(plan.consumed))
            }
            Err(e) => {
                if crate::config::env::joinir_dev::strict_enabled() {
                    use crate::mir::join_ir::lowering::error_tags;
                    return Err(error_tags::freeze_with_hint(
                        "phase134/suffix_router/execute",
                        &e,
                        "Loop suffix should be supported by Normalized but execution failed",
                    ));
                }
                trace.routing("suffix_router/error", func_name, &e);
                Ok(None) // Non-strict: fallback
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::ast::{ASTNode, LiteralValue, Span};

    #[test]
    fn test_try_lower_loop_suffix_phase132_pattern() {
        // This is an integration test that would require full MirBuilder setup
        // For now, we test the pattern detection logic

        let span = Span::unknown();
        let remaining = vec![
            ASTNode::Loop {
                condition: Box::new(ASTNode::Literal {
                    value: LiteralValue::Bool(true),
                    span: span.clone(),
                }),
                body: vec![
                    ASTNode::Assignment {
                        target: Box::new(ASTNode::Variable {
                            name: "x".to_string(),
                            span: span.clone(),
                        }),
                        value: Box::new(ASTNode::Literal {
                            value: LiteralValue::Integer(1),
                            span: span.clone(),
                        }),
                        span: span.clone(),
                    },
                    ASTNode::Break { span: span.clone() },
                ],
                span: span.clone(),
            },
            ASTNode::Assignment {
                target: Box::new(ASTNode::Variable {
                    name: "x".to_string(),
                    span: span.clone(),
                }),
                value: Box::new(ASTNode::BinaryOp {
                    left: Box::new(ASTNode::Variable {
                        name: "x".to_string(),
                        span: span.clone(),
                    }),
                    operator: crate::ast::BinaryOperator::Add,
                    right: Box::new(ASTNode::Literal {
                        value: LiteralValue::Integer(2),
                        span: span.clone(),
                    }),
                    span: span.clone(),
                }),
                span: span.clone(),
            },
            ASTNode::Return {
                value: Some(Box::new(ASTNode::Variable {
                    name: "x".to_string(),
                    span: span.clone(),
                })),
                span: span.clone(),
            },
        ];

        // Pattern should be detected (at least 2 statements, first is Loop)
        assert!(remaining.len() >= 2);
        assert!(matches!(&remaining[0], ASTNode::Loop { .. }));

        // Full lowering test would require MirBuilder setup
        // This validates the pattern structure
    }

    #[test]
    fn test_try_lower_loop_suffix_no_match_too_short() {
        // Single statement - should not match
        let span = Span::unknown();
        let remaining = vec![
            ASTNode::Loop {
                condition: Box::new(ASTNode::Literal {
                    value: LiteralValue::Bool(true),
                    span: span.clone(),
                }),
                body: vec![ASTNode::Break { span: span.clone() }],
                span: span.clone(),
            },
        ];

        // Pattern should not match (need at least 2 statements)
        assert!(remaining.len() < 2);
    }

    #[test]
    fn test_try_lower_loop_suffix_no_match_not_loop() {
        // First statement is not a loop
        let span = Span::unknown();
        let remaining = vec![
            ASTNode::Assignment {
                target: Box::new(ASTNode::Variable {
                    name: "x".to_string(),
                    span: span.clone(),
                }),
                value: Box::new(ASTNode::Literal {
                    value: LiteralValue::Integer(1),
                    span: span.clone(),
                }),
                span: span.clone(),
            },
            ASTNode::Return {
                value: Some(Box::new(ASTNode::Variable {
                    name: "x".to_string(),
                    span: span.clone(),
                })),
                span: span.clone(),
            },
        ];

        // Pattern should not match (first statement is not Loop)
        assert!(!matches!(&remaining[0], ASTNode::Loop { .. }));
    }
}
