use super::helpers::create_phi_bindings;
use super::{CoreEffectPlan, CoreLoopPlan, CorePhiInfo, CorePlan, Pattern2BreakPlan};
use crate::mir::basic_block::EdgeArgs;
use crate::mir::builder::control_flow::edgecfg::api::{BranchStub, EdgeStub, ExitKind, Frag};
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
use crate::mir::builder::MirBuilder;
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use crate::mir::{BinaryOp, ConstValue, MirType};
use std::collections::BTreeMap;

impl super::PlanNormalizer {
    /// Pattern2Break → CorePlan 変換
    ///
    /// CFG structure (6 blocks):
    /// ```
    /// preheader → header(PHI: i_current, carrier_current)
    ///               ↓
    ///            body(break_cond check)
    ///               ↓
    ///          ┌────┴────┐
    ///     break_then    step
    ///     (optional      ↓
    ///      update)    header (back-edge)
    ///          ↓
    ///        after_bb(PHI: carrier_out)
    ///          ↑
    ///        header (natural exit when !cond_loop)
    /// ```
    ///
    /// Key: after_bb PHI merges break path and natural exit path carrier values.
    pub(super) fn normalize_pattern2_break(
        builder: &mut MirBuilder,
        parts: Pattern2BreakPlan,
        ctx: &LoopPatternContext,
    ) -> Result<CorePlan, String> {
        use crate::mir::builder::control_flow::joinir::trace;

        let trace_logger = trace::trace();
        let debug = ctx.debug;

        if debug {
            trace_logger.debug(
                "normalizer/pattern2_break",
                &format!(
                    "Phase 286 P3.1: Normalizing Pattern2Break for {} (loop_var={}, carrier_var={})",
                    ctx.func_name, parts.loop_var, parts.carrier_var
                ),
            );
        }

        // Step 1: Block allocation (6 blocks)
        let preheader_bb = builder
            .current_block
            .ok_or_else(|| "Pattern2Break: no current block".to_string())?;
        let header_bb = builder.next_block_id();
        let body_bb = builder.next_block_id();
        let break_then_bb = builder.next_block_id();
        let step_bb = builder.next_block_id();
        let after_bb = builder.next_block_id();

        if debug {
            trace_logger.debug(
                "normalizer/pattern2_break",
                &format!(
                    "Block allocation: preheader={:?}, header={:?}, body={:?}, break_then={:?}, step={:?}, after={:?}",
                    preheader_bb, header_bb, body_bb, break_then_bb, step_bb, after_bb
                ),
            );
        }

        // Step 2: Get initial values from variable_map
        let loop_var_init = builder
            .variable_ctx
            .variable_map
            .get(&parts.loop_var)
            .copied()
            .ok_or_else(|| {
                format!(
                    "Pattern2Break: loop_var '{}' not in variable_map",
                    parts.loop_var
                )
            })?;

        let carrier_init = builder
            .variable_ctx
            .variable_map
            .get(&parts.carrier_var)
            .copied()
            .ok_or_else(|| {
                format!(
                    "Pattern2Break: carrier_var '{}' not in variable_map",
                    parts.carrier_var
                )
            })?;

        // Step 3: ValueId allocation
        let loop_var_current = builder.alloc_typed(MirType::Integer);
        let carrier_current = builder.alloc_typed(MirType::Integer);
        let cond_loop = builder.alloc_typed(MirType::Bool);
        let cond_break = builder.alloc_typed(MirType::Bool);
        let carrier_break = builder.alloc_typed(MirType::Integer);
        let carrier_step = builder.alloc_typed(MirType::Integer);
        let loop_var_next = builder.alloc_typed(MirType::Integer);
        let carrier_out = builder.alloc_typed(MirType::Integer);

        // Step 4: phi_bindings for AST lowering
        let phi_bindings = create_phi_bindings(&[
            (&parts.loop_var, loop_var_current),
            (&parts.carrier_var, carrier_current),
        ]);

        // Step 5: Lower AST expressions
        let (loop_cond_lhs, loop_cond_op, loop_cond_rhs, loop_cond_consts) =
            Self::lower_compare_ast(&parts.loop_condition, builder, &phi_bindings)?;

        let (break_cond_lhs, break_cond_op, break_cond_rhs, break_cond_consts) =
            Self::lower_compare_ast(&parts.break_condition, builder, &phi_bindings)?;

        let break_then_effects = if let Some(ref break_update_ast) = parts.carrier_update_in_break {
            let (lhs, op, rhs, consts) =
                Self::lower_binop_ast(break_update_ast, builder, &phi_bindings)?;
            let mut effects = consts;
            effects.push(CoreEffectPlan::BinOp {
                dst: carrier_break,
                lhs,
                op,
                rhs,
            });
            effects
        } else {
            let zero = builder.alloc_typed(MirType::Integer);
            vec![
                CoreEffectPlan::Const {
                    dst: zero,
                    value: ConstValue::Integer(0),
                },
                CoreEffectPlan::BinOp {
                    dst: carrier_break,
                    lhs: carrier_current,
                    op: BinaryOp::Add,
                    rhs: zero,
                },
            ]
        };

        let (carrier_lhs, carrier_op, carrier_rhs, carrier_consts) =
            Self::lower_binop_ast(&parts.carrier_update_in_body, builder, &phi_bindings)?;

        let (loop_inc_lhs, loop_inc_op, loop_inc_rhs, loop_inc_consts) =
            Self::lower_binop_ast(&parts.loop_increment, builder, &phi_bindings)?;

        // Step 6: Build header_effects
        let mut header_effects = loop_cond_consts;
        header_effects.push(CoreEffectPlan::Compare {
            dst: cond_loop,
            lhs: loop_cond_lhs,
            op: loop_cond_op,
            rhs: loop_cond_rhs,
        });

        // Step 7: Build body plans (break condition check)
        let mut body_plans: Vec<CorePlan> = Vec::new();
        for const_effect in break_cond_consts {
            body_plans.push(CorePlan::Effect(const_effect));
        }
        body_plans.push(CorePlan::Effect(CoreEffectPlan::Compare {
            dst: cond_break,
            lhs: break_cond_lhs,
            op: break_cond_op,
            rhs: break_cond_rhs,
        }));

        // Step 8: Build step_effects
        let mut step_effects = carrier_consts;
        step_effects.push(CoreEffectPlan::BinOp {
            dst: carrier_step,
            lhs: carrier_lhs,
            op: carrier_op,
            rhs: carrier_rhs,
        });
        step_effects.extend(loop_inc_consts);
        step_effects.push(CoreEffectPlan::BinOp {
            dst: loop_var_next,
            lhs: loop_inc_lhs,
            op: loop_inc_op,
            rhs: loop_inc_rhs,
        });

        // Step 9: Build block_effects
        let block_effects = vec![
            (preheader_bb, vec![]),
            (header_bb, header_effects),
            (body_bb, vec![]),
            (break_then_bb, break_then_effects),
            (step_bb, step_effects),
        ];

        // Step 10: Build PHIs
        let phis = vec![
            CorePhiInfo {
                block: header_bb,
                dst: loop_var_current,
                inputs: vec![(preheader_bb, loop_var_init), (step_bb, loop_var_next)],
                tag: format!("loop_var_{}", parts.loop_var),
            },
            CorePhiInfo {
                block: header_bb,
                dst: carrier_current,
                inputs: vec![(preheader_bb, carrier_init), (step_bb, carrier_step)],
                tag: format!("carrier_{}", parts.carrier_var),
            },
            CorePhiInfo {
                block: after_bb,
                dst: carrier_out,
                inputs: vec![(header_bb, carrier_current), (break_then_bb, carrier_break)],
                tag: format!("after_{}", parts.carrier_var),
            },
        ];

        // Step 11: Build Frag
        let empty_args = EdgeArgs {
            layout: JumpArgsLayout::CarriersOnly,
            values: vec![],
        };

        let branches = vec![
            BranchStub {
                from: header_bb,
                cond: cond_loop,
                then_target: body_bb,
                else_target: after_bb,
                then_args: empty_args.clone(),
                else_args: empty_args.clone(),
            },
            BranchStub {
                from: body_bb,
                cond: cond_break,
                then_target: break_then_bb,
                else_target: step_bb,
                then_args: empty_args.clone(),
                else_args: empty_args.clone(),
            },
        ];

        let wires = vec![
            EdgeStub {
                from: break_then_bb,
                kind: ExitKind::Normal,
                target: Some(after_bb),
                args: empty_args.clone(),
            },
            EdgeStub {
                from: step_bb,
                kind: ExitKind::Normal,
                target: Some(header_bb),
                args: empty_args.clone(),
            },
        ];

        let frag = Frag {
            entry: header_bb,
            exits: BTreeMap::new(),
            wires,
            branches,
        };

        // Step 12: Build final_values
        let final_values = vec![
            (parts.loop_var.clone(), loop_var_current),
            (parts.carrier_var.clone(), carrier_out),
        ];

        // Step 13: Build CoreLoopPlan
        let loop_plan = CoreLoopPlan {
            preheader_bb,
            header_bb,
            body_bb,
            step_bb,
            after_bb,
            found_bb: after_bb,
            body: body_plans,
            cond_loop,
            cond_match: cond_break,
            block_effects,
            phis,
            frag,
            final_values,
        };

        if debug {
            trace_logger.debug(
                "normalizer/pattern2_break",
                "CorePlan construction complete (6 blocks, 3 PHIs, after_bb PHI is key!)",
            );
        }

        Ok(CorePlan::Loop(loop_plan))
    }
}
