use crate::mir::join_ir::lowering::carrier_info::CarrierInfo;
use crate::mir::join_ir::lowering::debug_output_box::DebugOutputBox;
use crate::mir::join_ir::lowering::loop_update_analyzer::{UpdateExpr, UpdateRhs};
use crate::mir::join_ir::{BinOpKind, JoinInst, MirLikeInst};
use crate::mir::ValueId;
use std::collections::BTreeMap;

pub(crate) fn emit_carrier_updates(
    carrier_info: &CarrierInfo,
    carrier_updates: &BTreeMap<String, UpdateExpr>,
    carrier_param_ids: &[ValueId],
    carrier_next_ids: &[ValueId],
    carrier_merged_ids: &[ValueId],
    continue_cond: ValueId,
    const_1: ValueId,
    i_next: ValueId,
    debug: &DebugOutputBox,
    body: &mut Vec<JoinInst>,
) -> Result<(), String> {
    let carrier_count = carrier_info.carriers.len();
    debug_assert_eq!(carrier_param_ids.len(), carrier_count);
    debug_assert_eq!(carrier_next_ids.len(), carrier_count);
    debug_assert_eq!(carrier_merged_ids.len(), carrier_count);

    for idx in 0..carrier_count {
        let carrier_param = carrier_param_ids[idx];
        let carrier_next = carrier_next_ids[idx];
        let carrier_merged = carrier_merged_ids[idx];
        let carrier_name = &carrier_info.carriers[idx].name;

        debug.log(
            "carrier_update",
            &format!("Processing carrier '{}' (idx={})", carrier_name, idx),
        );
        let rhs = if let Some(update_expr) = carrier_updates.get(carrier_name) {
            debug.log(
                "carrier_update",
                &format!("Found update expr: {:?}", update_expr),
            );
            match update_expr {
                UpdateExpr::BinOp { op, rhs, .. } => {
                    if *op != BinOpKind::Add {
                        debug.log(
                            "warn",
                            &format!(
                                "Carrier '{}' uses unsupported operator {:?}, defaulting to Add",
                                carrier_name, op
                            ),
                        );
                    }

                    match rhs {
                        UpdateRhs::Const(n) => {
                            if *n == 1 {
                                const_1
                            } else {
                                debug.log(
                                    "warn",
                                    &format!(
                                        "Carrier '{}' uses const {}, only const_1 is pre-allocated, using const_1",
                                        carrier_name, n
                                    ),
                                );
                                const_1
                            }
                        }
                        UpdateRhs::Variable(var_name) => {
                            if var_name == &carrier_info.loop_var_name {
                                debug.log(
                                    "carrier_update",
                                    &format!(
                                        "Using i_next (ValueId({})) for variable '{}'",
                                        i_next.0, var_name
                                    ),
                                );
                                i_next
                            } else {
                                debug.log(
                                    "warn",
                                    &format!(
                                        "Carrier '{}' updates with unknown variable '{}', using const_1",
                                        carrier_name, var_name
                                    ),
                                );
                                const_1
                            }
                        }
                        UpdateRhs::NumberAccumulation { .. } => {
                            debug.log(
                                "phase190",
                                &format!(
                                    "Carrier '{}' has number accumulation - not supported in Pattern 4, using Select passthrough",
                                    carrier_name
                                ),
                            );
                            body.push(JoinInst::Select {
                                dst: carrier_merged,
                                cond: continue_cond,
                                then_val: carrier_param,
                                else_val: carrier_param,
                                type_hint: None,
                            });
                            continue;
                        }
                        UpdateRhs::StringLiteral(_) | UpdateRhs::Other => {
                            debug.log(
                                "phase178",
                                &format!(
                                    "Carrier '{}' has string/complex update - skipping BinOp, using Select passthrough",
                                    carrier_name
                                ),
                            );
                            body.push(JoinInst::Select {
                                dst: carrier_merged,
                                cond: continue_cond,
                                then_val: carrier_param,
                                else_val: carrier_param,
                                type_hint: None,
                            });
                            continue;
                        }
                    }
                }
                UpdateExpr::Const(n) => {
                    if *n == 1 {
                        const_1
                    } else {
                        debug.log(
                            "warn",
                            &format!(
                                "Carrier '{}' uses const {}, only const_1 is pre-allocated, using const_1",
                                carrier_name, n
                            ),
                        );
                        const_1
                    }
                }
            }
        } else {
            debug.log(
                "warn",
                &format!(
                    "No update expression for carrier '{}', defaulting to +1",
                    carrier_name
                ),
            );
            const_1
        };

        debug.log(
            "carrier_update",
            &format!(
                "Generating: ValueId({}) = ValueId({}) + ValueId({})",
                carrier_next.0, carrier_param.0, rhs.0
            ),
        );
        body.push(JoinInst::Compute(MirLikeInst::BinOp {
            dst: carrier_next,
            op: BinOpKind::Add,
            lhs: carrier_param,
            rhs,
        }));

        body.push(JoinInst::Select {
            dst: carrier_merged,
            cond: continue_cond,
            then_val: carrier_param,
            else_val: carrier_next,
            type_hint: None,
        });
    }

    Ok(())
}
