//! Phase 33-21: Pattern 4 (Loop with Continue) Implementation
//!
//! **Current Status**: Fully implemented using Select-based continue semantics.
//!
//! ## Implementation Approach
//!
//! Continue is handled via Select instruction for carrier updates:
//! - When continue condition is true: carrier keeps its value (no update)
//! - When continue condition is false: carrier gets updated value
//!
//! This avoids the complexity of explicit latch blocks by using PHI-based
//! value selection at each iteration.
//!
//! ## Example
//!
//! ```nyash
//! local i = 0
//! local sum = 0
//! loop(i < 10) {
//!   i = i + 1
//!   if i % 2 == 0 { continue }  // Skip even numbers
//!   sum = sum + i
//! }
//! // sum = 25 (1+3+5+7+9)
//! ```
//!
//! ## Key Implementation Details
//!
//! - **Select instruction**: Used to conditionally skip carrier updates
//! - **Header PHI**: Tracks carrier values across iterations
//! - **ExitMeta**: Maps final carrier values to host variable slots
//! - **Phase 33-21 fix**: Correct remapping of function parameters to header PHI dsts

use super::super::trace;
use crate::ast::ASTNode;
use crate::mir::builder::MirBuilder;
use crate::mir::join_ir::lowering::loop_update_analyzer::UpdateExpr;
use crate::mir::loop_pattern_detection::error_messages;
use crate::mir::ValueId;
use std::collections::BTreeMap;

/// Phase 142 P2: Detect return statements in loop body
///
/// This is a helper function for Fail-Fast behavior when return statements
/// are detected in Pattern4 (continue) loops, which are not yet fully supported.
///
/// # Arguments
///
/// * `body` - Loop body statements to scan
///
/// # Returns
///
/// `true` if at least one return statement is found in the body
fn has_return_in_body(body: &[ASTNode]) -> bool {
    for stmt in body {
        if has_return_node(stmt) {
            return true;
        }
    }
    false
}

/// Helper: Recursively check if node or its children contain return
fn has_return_node(node: &ASTNode) -> bool {
    match node {
        ASTNode::Return { .. } => true,
        ASTNode::If {
            then_body,
            else_body,
            ..
        } => {
            then_body.iter().any(|n| has_return_node(n))
                || else_body
                    .as_ref()
                    .map_or(false, |body| body.iter().any(|n| has_return_node(n)))
        }
        ASTNode::Loop { body, .. } => {
            // Nested loops: scan recursively (though not common in our patterns)
            body.iter().any(|n| has_return_node(n))
        }
        _ => false,
    }
}

/// Phase 194+: Detection function for Pattern 4
///
/// Phase 192: Updated to use pattern_kind for consistency
/// Phase 178: Added string carrier rejection (unsupported by Pattern 4)
/// Phase 187-2: No legacy fallback - rejection means error
///
/// Pattern 4 matches loops with continue statements.
///
/// # Structure-based Detection (Phase 194+)
///
/// Uses pattern classification from LoopPatternContext:
/// - ctx.pattern_kind == Pattern4Continue
///
/// This is structure-based detection that does NOT depend on function names
/// or variable names like "sum".
///
/// # Detection Rules
///
/// 1. **Must have continue**: `ctx.has_continue == true`
/// 2. **No break statements**: `ctx.has_break == false` (for simplicity in Pattern 4)
/// 3. **Phase 178**: No string/complex carrier updates (JoinIR doesn't support string concat)
///
/// If all conditions are met, Pattern 4 is detected.
pub(crate) fn can_lower(builder: &MirBuilder, ctx: &super::router::LoopPatternContext) -> bool {
    use super::common_init::CommonPatternInitializer;
    use crate::mir::loop_pattern_detection::LoopPatternKind;

    // Basic pattern check
    if ctx.pattern_kind != LoopPatternKind::Pattern4Continue {
        return false;
    }

    // Phase 188/Refactor: Use common carrier update validation
    // Extracts loop variable for dummy carrier creation (not used but required by API)
    let loop_var_name = match builder.extract_loop_variable_from_condition(ctx.condition) {
        Ok(name) => name,
        Err(_) => return false,
    };

    CommonPatternInitializer::check_carrier_updates_allowed(
        ctx.body,
        &loop_var_name,
        &builder.variable_ctx.variable_map,
    )
}

/// Phase 33-19: Lowering function for Pattern 4
///
/// Wrapper around cf_loop_pattern4_with_continue to match router signature.
///
/// # Implementation (Phase 195-197)
///
/// 1. Extract loop variables from condition
/// 2. Generate JoinIR with continue support (lower_loop_with_continue_minimal)
/// 3. Convert JoinModule → MirModule
/// 4. Create JoinInlineBoundary for input/output mapping
/// 5. Merge MIR blocks into current_function
/// 6. Return loop result (first carrier value)
pub(crate) fn lower(
    builder: &mut MirBuilder,
    ctx: &super::router::LoopPatternContext,
) -> Result<Option<ValueId>, String> {
    // Phase 142 P2: Check for return statements (not yet supported)
    if has_return_in_body(ctx.body) {
        return Err(
            "[Pattern4] Early return is not yet supported in continue loops. \
             This will be implemented in Phase 142 P2. \
             Pattern: loop with both continue and return statements."
                .to_string(),
        );
    }

    // Phase 33-19: Connect stub to actual implementation
    builder.cf_loop_pattern4_with_continue(ctx.condition, ctx.body, ctx.func_name, ctx.debug)
}

impl MirBuilder {
    /// Phase 179-B: Pattern 4 (Loop with Continue) lowerer
    ///
    /// **Refactored**: Now uses PatternPipelineContext for unified preprocessing
    ///
    /// # Pipeline (Phase 179-B)
    /// 1. Build preprocessing context → PatternPipelineContext
    /// 2. Pattern 4-specific processing (continue normalization, carrier analysis)
    /// 3. Call JoinIR lowerer → JoinModule
    /// 4. Create boundary from context → JoinInlineBoundary
    /// 5. Merge MIR blocks → JoinIRConversionPipeline
    ///
    /// # Example
    ///
    /// ```nyash
    /// local i = 0
    /// local sum = 0
    /// loop(i < 10) {
    ///   i = i + 1
    ///   if (i % 2 == 0) {
    ///     continue  // Skip even numbers
    ///   }
    ///   sum = sum + i
    /// }
    /// // sum = 25 (1+3+5+7+9)
    /// ```
    ///
    /// Note: Pattern 4 has complex carrier analysis logic that remains inline
    /// for now, using Pattern4CarrierAnalyzer for Select-based continue semantics.
    pub(in crate::mir::builder) fn cf_loop_pattern4_with_continue(
        &mut self,
        condition: &ASTNode,
        _body: &[ASTNode],
        _func_name: &str,
        debug: bool,
    ) -> Result<Option<ValueId>, String> {
        // Phase 195: Use unified trace
        trace::trace().debug("pattern4", "Calling Pattern 4 minimal lowerer");

        let prepared = prepare_pattern4_context(self, condition, _body)?;
        lower_pattern4_joinir(self, condition, &prepared, debug)
    }
}

/// Preprocessed data for Pattern 4 lowering.
struct Pattern4Prepared {
    loop_var_name: String,
    loop_scope: crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape,
    carrier_info: crate::mir::join_ir::lowering::carrier_info::CarrierInfo,
    carrier_updates: BTreeMap<String, UpdateExpr>,
}

/// Normalize, build context, analyze carriers, and promote loop-body locals.
fn prepare_pattern4_context(
    builder: &mut MirBuilder,
    condition: &ASTNode,
    body: &[ASTNode],
) -> Result<Pattern4Prepared, String> {
    use super::pattern4_carrier_analyzer::Pattern4CarrierAnalyzer;
    use super::pattern_pipeline::{build_pattern_context, PatternVariant};
    use crate::mir::loop_pattern_detection::loop_body_cond_promoter::{
        ConditionPromotionRequest, ConditionPromotionResult, LoopBodyCondPromoter,
    };
    use crate::mir::loop_pattern_detection::loop_condition_scope::LoopConditionScopeBox;

    // Normalize continue branches for analysis/lowering
    let normalized_body = Pattern4CarrierAnalyzer::normalize_continue_branches(body);

    // Build preprocessing context
    let ctx = build_pattern_context(
        builder,
        condition,
        &normalized_body,
        PatternVariant::Pattern4,
    )?;

    let loop_var_name = ctx.loop_var_name.clone();
    let loop_scope = ctx.loop_scope.clone();
    let carrier_info_prelim = ctx.carrier_info.clone();

    // Analyze carrier updates and filter carriers
    let carrier_updates = Pattern4CarrierAnalyzer::analyze_carrier_updates(
        &normalized_body,
        &carrier_info_prelim.carriers,
    );
    let mut carrier_info =
        Pattern4CarrierAnalyzer::analyze_carriers(&normalized_body, &carrier_info_prelim)?;

    trace::trace().debug(
        "pattern4",
        &format!(
            "CarrierInfo: loop_var={}, carriers={:?}",
            carrier_info.loop_var_name,
            carrier_info
                .carriers
                .iter()
                .map(|c| &c.name)
                .collect::<Vec<_>>()
        ),
    );

    trace::trace().debug(
        "pattern4",
        &format!(
            "Analyzed {} carrier update expressions",
            carrier_updates.len()
        ),
    );
    for (carrier_name, update_expr) in &carrier_updates {
        trace::trace().debug(
            "pattern4",
            &format!("  {} → {:?}", carrier_name, update_expr),
        );
    }

    // LoopBodyLocal promotion for conditions (skip_whitespace etc.)
    let continue_cond = LoopBodyCondPromoter::extract_continue_condition(&normalized_body);
    let conditions_to_analyze: Vec<&ASTNode> = if let Some(cont_cond) = continue_cond {
        vec![condition, cont_cond]
    } else {
        vec![condition]
    };

    let cond_scope =
        LoopConditionScopeBox::analyze(&loop_var_name, &conditions_to_analyze, Some(&loop_scope));

    if cond_scope.has_loop_body_local() {
        let promotion_req = ConditionPromotionRequest {
            loop_param_name: &loop_var_name,
            cond_scope: &cond_scope,
            scope_shape: Some(&loop_scope),
            break_cond: None, // Pattern 4 has no break
            continue_cond,
            loop_body: &normalized_body,
            #[cfg(feature = "normalized_dev")]
            // Phase 136 Step 4/7: Use binding_ctx for binding_map reference
            binding_map: Some(builder.binding_ctx.binding_map()),
        };

        match LoopBodyCondPromoter::try_promote_for_condition(promotion_req) {
            ConditionPromotionResult::Promoted {
                carrier_info: promoted_carrier,
                promoted_var,
                carrier_name,
            } => {
                trace::trace().debug(
                    "pattern4/cond_promoter",
                    &format!(
                        "LoopBodyLocal '{}' promoted to carrier '{}'",
                        promoted_var, carrier_name
                    ),
                );

                #[cfg(feature = "normalized_dev")]
                {
                    use crate::mir::join_ir::lowering::carrier_binding_assigner::CarrierBindingAssigner;
                    let mut promoted_carrier = promoted_carrier;
                    CarrierBindingAssigner::assign_promoted_binding(
                        builder,
                        &mut promoted_carrier,
                        &promoted_var,
                        &carrier_name,
                    )
                    .map_err(|e| format!("[phase78/binding_assign] {:?}", e))?;
                    carrier_info.merge_from(&promoted_carrier);
                }
                #[cfg(not(feature = "normalized_dev"))]
                {
                    carrier_info.merge_from(&promoted_carrier);
                }

                trace::trace().debug(
                    "pattern4/cond_promoter",
                    &format!(
                        "Merged carrier '{}' into CarrierInfo (total carriers: {})",
                        carrier_name,
                        carrier_info.carrier_count()
                    ),
                );

                if let Some(helper) = carrier_info.trim_helper() {
                    if helper.is_safe_trim() {
                        trace::trace().debug(
                            "pattern4/cond_promoter",
                            "Safe Trim/skip_whitespace pattern detected",
                        );
                        trace::trace().debug(
                            "pattern4/cond_promoter",
                            &format!(
                                "Carrier: '{}', original var: '{}', whitespace chars: {:?}",
                                helper.carrier_name, helper.original_var, helper.whitespace_chars
                            ),
                        );
                    } else {
                        return Err(error_messages::format_error_pattern4_trim_not_safe(
                            &helper.carrier_name,
                            helper.whitespace_count(),
                        ));
                    }
                }
            }
            ConditionPromotionResult::CannotPromote { reason, vars } => {
                return Err(error_messages::format_error_pattern4_promotion_failed(
                    &vars, &reason,
                ));
            }
        }
    }

    Ok(Pattern4Prepared {
        loop_var_name,
        loop_scope,
        carrier_info,
        carrier_updates,
    })
}

/// JoinIR lowering stage for Pattern 4 using prepared context.
fn lower_pattern4_joinir(
    builder: &mut MirBuilder,
    condition: &ASTNode,
    prepared: &Pattern4Prepared,
    debug: bool,
) -> Result<Option<ValueId>, String> {
    use super::super::merge::exit_line::meta_collector::ExitMetaCollector;
    use super::conversion_pipeline::JoinIRConversionPipeline;
    use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
    use crate::mir::join_ir::lowering::loop_with_continue_minimal::lower_loop_with_continue_minimal;
    use crate::mir::join_ir::lowering::JoinInlineBoundaryBuilder;

    trace::trace().varmap("pattern4_start", &builder.variable_ctx.variable_map);

    let mut join_value_space = JoinValueSpace::new();

    #[cfg(feature = "normalized_dev")]
    // Phase 136 Step 4/7: Use binding_ctx for binding_map clone
    let binding_map_clone = builder.binding_ctx.binding_map().clone();

    let (join_module, exit_meta) = match lower_loop_with_continue_minimal(
        prepared.loop_scope.clone(),
        condition,
        builder,
        &prepared.carrier_info,
        &prepared.carrier_updates,
        &mut join_value_space,
        #[cfg(feature = "normalized_dev")]
        Some(&binding_map_clone),
    ) {
        Ok(result) => result,
        Err(e) => {
            trace::trace().debug("pattern4", &format!("Pattern 4 lowerer failed: {}", e));
            return Err(error_messages::format_error_pattern4_lowering_failed(&e));
        }
    };

    trace::trace().debug(
        "pattern4",
        &format!("ExitMeta: {} exit bindings", exit_meta.exit_values.len()),
    );
    for (carrier_name, join_value) in &exit_meta.exit_values {
        trace::trace().debug(
            "pattern4",
            &format!("  {} → ValueId({})", carrier_name, join_value.0),
        );
    }

    let exit_bindings = ExitMetaCollector::collect(
        builder,
        &exit_meta,
        Some(&prepared.carrier_info), // Phase 228-8: Include ConditionOnly carriers
        debug,
    );

    for carrier in &prepared.carrier_info.carriers {
        if !exit_bindings.iter().any(|b| b.carrier_name == carrier.name) {
            return Err(error_messages::format_error_pattern4_carrier_not_found(
                &carrier.name,
            ));
        }
    }

    // Build inputs for boundary: [loop_var, carriers...]
    let mut host_inputs = vec![prepared.carrier_info.loop_var_id];
    for carrier in &prepared.carrier_info.carriers {
        host_inputs.push(carrier.host_id);
    }

    trace::trace().debug(
        "pattern4",
        &format!(
            "host_inputs: {:?}",
            host_inputs.iter().map(|v| v.0).collect::<Vec<_>>()
        ),
    );

    let mut join_inputs = vec![ValueId(0)]; // ValueId(0) = i_init in JoinIR
    for idx in 0..prepared.carrier_info.carriers.len() {
        join_inputs.push(ValueId((idx + 1) as u32)); // ValueId(1..N) = carrier inits
    }

    trace::trace().debug(
        "pattern4",
        &format!(
            "join_inputs: {:?}",
            join_inputs.iter().map(|v| v.0).collect::<Vec<_>>()
        ),
    );

    let boundary = JoinInlineBoundaryBuilder::new()
        .with_inputs(join_inputs, host_inputs) // Dynamic carrier count
        .with_exit_bindings(exit_bindings)
        .with_loop_var_name(Some(prepared.loop_var_name.clone()))
        .with_carrier_info(prepared.carrier_info.clone())
        .build();

    let _result_val = JoinIRConversionPipeline::execute(
        builder,
        join_module,
        Some(&boundary),
        "pattern4",
        debug,
    )?;

    let void_val = crate::mir::builder::emission::constant::emit_void(builder);
    trace::trace().debug(
        "pattern4",
        &format!("Loop complete, returning Void {:?}", void_val),
    );

    Ok(Some(void_val))
}
