//! Phase 188.3: Pattern6 NestedLoopMinimal - 1-level nested loop lowering
//!
//! Handles loops of the form:
//! ```nyash
//! loop(outer_cond) {
//!     loop(inner_cond) {
//!         // inner body
//!     }
//!     // outer body (after inner loop)
//! }
//! ```
//!
//! Requirements (Pattern1 for both):
//! - Outer loop: no break, no continue (Pattern1)
//! - Inner loop: no break, no continue (Pattern1)
//! - Exactly 1 inner loop
//! - max_loop_depth == 2
//!
//! Strategy:
//! - Generate outer_step continuation (contains inner loop call)
//! - Generate inner_step continuation (tail recursion)
//! - Generate k_inner_exit (bridges to outer continuation)
//! - Wire continuations

use crate::ast::ASTNode;
use crate::mir::builder::control_flow::joinir::patterns::LoopPatternContext;
use crate::mir::builder::MirBuilder;
use crate::mir::loop_pattern_detection::LoopPatternKind;
use crate::mir::ValueId;

/// Phase 188.3: Validate strict mode constraints
///
/// Requirements (most already checked in is_pattern6_lowerable):
/// - Inner loop has no break (checked in routing.rs)
/// - Inner loop has no continue (checked in routing.rs)
/// - Outer loop has no break (checked in routing.rs)
/// - Outer loop has no continue (checked in routing.rs)
///
/// Additional checks (Phase 188.4+):
/// - Outer variable write-back detection (TODO: add to is_pattern6_lowerable)
///
/// This function serves as final safety check before lowering.
/// If validation fails → Fail-Fast (not silent fallback).
fn validate_strict_mode(_inner_ast: &ASTNode, _ctx: &LoopPatternContext) -> Result<(), String> {
    // Phase 188.3: Most validation already done in is_pattern6_lowerable()
    // This is a placeholder for future strict mode checks

    // Future Phase 188.4+ checks:
    // - Detect outer variable write-back in inner loop body
    // - Validate carrier compatibility
    // - Check for unsupported AST patterns

    Ok(())
}

/// Phase 188.3: Extract inner loop AST from outer loop body
///
/// Requirements:
/// - Outer body must contain exactly 1 Loop node
/// - 0 loops → Error (shouldn't happen after Pattern6 selection)
/// - 2+ loops → Error (multiple inner loops not supported)
///
/// Returns reference to inner loop ASTNode
fn extract_inner_loop_ast<'a>(ctx: &'a LoopPatternContext) -> Result<&'a ASTNode, String> {
    // Find all Loop nodes in outer body
    let mut inner_loop: Option<&ASTNode> = None;
    let mut loop_count = 0;

    for stmt in ctx.body.iter() {
        if matches!(stmt, ASTNode::Loop { .. }) {
            loop_count += 1;
            if inner_loop.is_none() {
                inner_loop = Some(stmt);
            }
        }
    }

    // Validate exactly 1 inner loop
    match loop_count {
        0 => Err(
            "[Pattern6/extract] No inner loop found (should not happen after Pattern6 selection)"
                .to_string(),
        ),
        1 => Ok(inner_loop.unwrap()), // Safe: loop_count == 1 guarantees Some
        _ => Err(format!(
            "[Pattern6/extract] Multiple inner loops ({}) not supported. \
             Phase 188.3 supports exactly 1 inner loop only.",
            loop_count
        )),
    }
}

/// Detect if this context can be lowered as Pattern6 (NestedLoopMinimal)
///
/// Pattern selection happens in choose_pattern_kind() (SSOT).
/// This function just verifies ctx.pattern_kind matches.
pub(crate) fn can_lower(_builder: &MirBuilder, ctx: &LoopPatternContext) -> bool {
    ctx.pattern_kind == LoopPatternKind::Pattern6NestedLoopMinimal
}

/// Lower Pattern6 (NestedLoopMinimal) to MIR
///
/// Phase 188.3 P1: Full implementation with JoinIR pipeline
pub(crate) fn lower(
    builder: &mut MirBuilder,
    ctx: &LoopPatternContext,
) -> Result<Option<ValueId>, String> {
    use super::super::trace;

    // Phase 3-1: Extract inner loop AST (validate exactly 1 inner loop)
    let _inner_ast = extract_inner_loop_ast(ctx)?;

    // Phase 3-2: Validate strict mode constraints (Fail-Fast)
    validate_strict_mode(_inner_ast, ctx)?;

    // Phase 3-3: Full implementation with JoinIR pipeline
    trace::trace().debug("pattern6", "Calling Pattern 6 nested loop minimal lowerer");

    // Build preprocessing context - Pattern6 shares Pattern1's infrastructure
    use super::pattern_pipeline::{build_pattern_context, PatternVariant};
    let pattern_ctx = build_pattern_context(builder, ctx.condition, ctx.body, PatternVariant::Pattern1)?;

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

    // Create JoinValueSpace for unified ValueId allocation
    use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
    let mut join_value_space = JoinValueSpace::new();

    // Call Pattern 6 lowerer with preprocessed scope
    use crate::mir::join_ir::lowering::nested_loop_minimal::lower_nested_loop_minimal;
    let join_module = match lower_nested_loop_minimal(pattern_ctx.loop_scope, &mut join_value_space) {
        Some(module) => module,
        None => {
            trace::trace().debug("pattern6", "Pattern 6 lowerer returned None");
            return Ok(None);
        }
    };

    // Create boundary from context
    // Phase 188.3: Critical - must include continuation_func_ids to prevent merge misdetection
    use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
    use crate::mir::join_ir::lowering::inline_boundary::LoopExitBinding;
    use crate::mir::join_ir::lowering::join_value_space::PARAM_MIN;
    use crate::mir::join_ir::lowering::JoinInlineBoundaryBuilder;
    use crate::mir::join_ir::lowering::nested_loop_minimal::{INNER_STEP, K_INNER_EXIT};

    // Extract k_exit's parameter ValueId from join_module
    let k_exit_func = join_module.require_function("k_exit", "Pattern 6");
    let sum_exit_value = k_exit_func
        .params
        .first()
        .copied()
        .expect("k_exit must have parameter for exit value (sum)");

    // Phase 188.3: Extract variables from variable_map
    let sum_var_id = builder
        .variable_ctx
        .variable_map
        .get("sum")
        .copied()
        .ok_or_else(|| "[Pattern6] sum variable not found in variable_map".to_string())?;

    let i_var_id = pattern_ctx.loop_var_id;

    // Create exit binding for sum (the final return value)
    let sum_exit_binding = LoopExitBinding {
        carrier_name: "sum".to_string(),
        join_exit_value: sum_exit_value,
        host_slot: sum_var_id,
        role: CarrierRole::LoopState,
    };

    // Phase 188.3 CRITICAL: Include continuation_func_ids to prevent merge from
    // selecting inner_step as loop header
    use std::collections::BTreeSet;
    let continuation_funcs = BTreeSet::from([
        "k_exit".to_string(),
        K_INNER_EXIT.to_string(),
        INNER_STEP.to_string(),
    ]);

    let boundary = JoinInlineBoundaryBuilder::new()
        .with_inputs(
            vec![ValueId(PARAM_MIN), ValueId(PARAM_MIN + 1)], // main(i0, sum0)
            vec![i_var_id, sum_var_id],                       // host variables
        )
        .with_exit_bindings(vec![sum_exit_binding])
        .with_loop_var_name(Some(pattern_ctx.loop_var_name.clone())) // Phase 188.3: Enables header PHI for 'i'
        .with_continuation_funcs(continuation_funcs)
        .build();

    // Use JoinIRConversionPipeline for unified conversion flow
    use super::conversion_pipeline::JoinIRConversionPipeline;
    let _ = JoinIRConversionPipeline::execute(
        builder,
        join_module,
        Some(&boundary),
        "pattern6",
        ctx.debug,
    )?;

    // Return Void (loops don't produce values)
    let void_val = crate::mir::builder::emission::constant::emit_void(builder);

    trace::trace().debug(
        "pattern6",
        &format!("Nested loop complete, returning Void {:?}", void_val),
    );

    Ok(Some(void_val))
}
