//! Match/expr-block lowering for JSON v0 bridge.

use super::super::ast::{ExprV0, MatchArmV0};
use super::expr::{lower_expr_with_scope, VarScope};
use super::merge::new_block;
use super::BridgeEnv;
use crate::ast::Span;
use crate::mir::{BasicBlockId, CompareOp, ConstValue, MirFunction, MirInstruction, ValueId};

pub(super) fn lower_match_expr_with_scope<S: VarScope>(
    env: &BridgeEnv,
    f: &mut MirFunction,
    cur_bb: BasicBlockId,
    scrutinee: &ExprV0,
    arms: &[MatchArmV0],
    else_expr: &ExprV0,
    vars: &mut S,
) -> Result<(ValueId, BasicBlockId), String> {
    // Evaluate scrutinee
    let (scr_val, start_bb) = lower_expr_with_scope(env, f, cur_bb, scrutinee, vars)?;

    // Set up blocks
    let dispatch_bb = new_block(f);
    if let Some(bb) = f.get_block_mut(start_bb) {
        if !bb.is_terminated() {
            crate::mir::ssot::cf_common::set_jump(f, start_bb, dispatch_bb);
        }
    }
    let else_bb = new_block(f);
    let merge_bb = new_block(f);

    // Chain dispatch over arms
    let mut cur_dispatch = dispatch_bb;
    let mut phi_inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
    for (i, arm) in arms.iter().enumerate() {
        let then_bb = new_block(f);
        let next_dispatch = if i + 1 < arms.len() {
            Some(new_block(f))
        } else {
            None
        };
        let fall_bb = next_dispatch.unwrap_or(else_bb);

        // Pre-allocate ids to avoid double borrow
        let ldst = f.next_value_id();
        let cond = f.next_value_id();
        if let Some(bb) = f.get_block_mut(cur_dispatch) {
            // compare scr_val == label
            bb.add_instruction(MirInstruction::Const {
                dst: ldst,
                value: ConstValue::String(arm.label.clone()),
            });
        }
        crate::mir::ssot::cf_common::emit_compare_func(
            f,
            cur_dispatch,
            cond,
            CompareOp::Eq,
            scr_val,
            ldst,
        );
        crate::mir::ssot::cf_common::set_branch(f, cur_dispatch, cond, then_bb, fall_bb);

        // Then arm body
        let (tval, tend) = lower_expr_with_scope(env, f, then_bb, &arm.expr, vars)?;
        if let Some(bb) = f.get_block_mut(tend) {
            if !bb.is_terminated() {
                crate::mir::ssot::cf_common::set_jump(f, tend, merge_bb);
            }
        }
        phi_inputs.push((tend, tval));

        cur_dispatch = fall_bb;
    }

    // Else body
    let (eval, eend) = lower_expr_with_scope(env, f, else_bb, else_expr, vars)?;
    if let Some(bb) = f.get_block_mut(eend) {
        if !bb.is_terminated() {
            crate::mir::ssot::cf_common::set_jump(f, eend, merge_bb);
        }
    }
    phi_inputs.push((eend, eval));

    // Merge result
    let out = f.next_value_id();
    // フェーズM.2: PHI統一処理（no_phi分岐削除）
    let inputs = phi_inputs;
    crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
        f,
        merge_bb,
        out,
        inputs,
        Span::unknown(),
    );
    Ok((out, merge_bb))
}
