//! 🎯 箱理論: 関数lowering処理
//!
//! 責務:
//! - static/instance method を MIR function に lowering
//! - BoxCompilationContext による完全独立化
//! - パラメータ・型情報の適切な管理

use super::function_lowering;
use crate::ast::ASTNode;
use crate::mir::builder::{MirBuilder, MirInstruction, MirType};
use crate::mir::region::function_slot_registry::FunctionSlotRegistry;
use crate::mir::{MirValueKind, ValueId}; // Phase 26-A-3: ValueId型安全化
use std::collections::BTreeMap; // Phase 25.1: 決定性確保

/// 🎯 箱理論: Lowering Context（準備と復元）
struct LoweringContext {
    context_active: bool,
    saved_var_map: Option<BTreeMap<String, super::super::ValueId>>, // Phase 25.1: BTreeMap化
    saved_static_ctx: Option<String>,
    saved_function: Option<super::super::MirFunction>,
    saved_block: Option<super::super::BasicBlockId>,
    saved_slot_registry: Option<FunctionSlotRegistry>,
}

impl MirBuilder {
    /// 🎯 箱理論: Step 1 - Lowering Context準備
    fn prepare_lowering_context(&mut self, func_name: &str) -> LoweringContext {
        // Static box context設定
        let saved_static_ctx = self.comp_ctx.current_static_box.clone();
        if let Some(pos) = func_name.find('.') {
            let box_name = &func_name[..pos];
            if !box_name.is_empty() {
                self.comp_ctx.current_static_box = Some(box_name.to_string());
            }
        }

        // BoxCompilationContext vs saved_var_map モード判定
        let context_active = self.comp_ctx.compilation_context.is_some();
        let saved_var_map = if !context_active {
            Some(std::mem::take(&mut self.variable_ctx.variable_map))
        } else {
            None
        };

        // 関数スコープ SlotRegistry は元の関数側から退避しておくよ。
        let saved_slot_registry = self.comp_ctx.current_slot_registry.take();

        // Phase 201-A: Clear reserved ValueIds at function entry (function-local).
        self.comp_ctx.clear_reserved_value_ids();

        // BoxCompilationContext mode: clear()で完全独立化
        if context_active {
            self.variable_ctx.variable_map.clear();
            self.type_ctx.value_origin_newbox.clear();
            // value_types も static box 単位で独立させる。
            // これにより、前の static box で使用された ValueId に紐づく型情報が
            // 次の box にリークして誤った box_name 推論（例: Stage1UsingResolverBox）
            // を引き起こすことを防ぐ。
            self.type_ctx.value_types.clear();
        }

        LoweringContext {
            context_active,
            saved_var_map,
            saved_static_ctx,
            saved_function: None,
            saved_block: None,
            saved_slot_registry,
        }
    }

    /// 🎯 箱理論: Step 2 - 関数スケルトン作成
    fn create_function_skeleton(
        &mut self,
        func_name: String,
        params: &[String],
        body: &[ASTNode],
        ctx: &mut LoweringContext,
    ) -> Result<(), String> {
        let signature =
            function_lowering::prepare_static_method_signature(func_name.clone(), params, body);
        let entry = self.next_block_id();
        let function = self.new_function_with_metadata(signature, entry);

        // Phase 136 Step 3/7: Save from scope_ctx (SSOT)
        ctx.saved_function = self.scope_ctx.current_function.take();
        ctx.saved_block = self.current_block.take();

        let trace = crate::mir::builder::control_flow::joinir::trace::trace();
        trace.emit_if(
            "debug",
            "create_function_skeleton",
            &format!("Creating function: {}", func_name),
            trace.is_enabled(),
        );
        trace.emit_if(
            "debug",
            "create_function_skeleton",
            &format!("Entry block: {:?}", entry),
            trace.is_enabled(),
        );

        // Phase 136 Step 3/7: Use scope_ctx as SSOT
        self.scope_ctx.current_function = Some(function);
        self.current_block = Some(entry);
        // 新しい関数スコープ用の SlotRegistry を準備するよ（観測専用）
        self.comp_ctx.current_slot_registry = Some(FunctionSlotRegistry::new());
        self.ensure_block_exists(entry)?;

        // Region 観測レイヤ: static 関数用の FunctionRegion を積むよ。
        crate::mir::region::observer::observe_function_region(self);

        Ok(())
    }

    /// 🎯 箱理論: Step 3 - パラメータ設定
    /// Phase 269 P1.2: static call 正規化により、static box では "me" の擬似初期化を行わない（receiver は compile-time で確定）
    #[allow(deprecated)]
    fn setup_function_params(&mut self, params: &[String]) {
        // Phase 136 Step 3/7: Clear scope_ctx (SSOT)
        self.scope_ctx.function_param_names.clear();
        // SlotRegistry 更新は borrow 競合を避けるため、まずローカルに集約してから反映するよ。
        let mut slot_regs: Vec<(String, Option<MirType>)> = Vec::new();
        // Phase 26-A-3: パラメータ型情報も後で一括登録（借用競合回避）
        let mut param_kinds: Vec<(ValueId, u32)> = Vec::new();

        if let Some(ref mut f) = self.scope_ctx.current_function {
            // 📦 Hotfix 5: Use pre-populated params from MirFunction::new()
            // Static methods have implicit receiver at params[0], so actual parameters start at offset
            let receiver_offset = if f.params.is_empty() {
                0
            } else {
                // If params already populated (by Hotfix 4+5), use them
                if f.params.len() > params.len() {
                    1
                } else {
                    0
                }
            };

            let param_types = f.signature.params.clone();

            for (idx, p) in params.iter().enumerate() {
                let param_idx = receiver_offset + idx;
                let pid = if param_idx < f.params.len() {
                    // Use pre-allocated ValueId from MirFunction::new()
                    f.params[param_idx]
                } else {
                    // Allocate new ValueId (fallback for non-static methods)
                    let new_pid = f.next_value_id();
                    f.params.push(new_pid);
                    new_pid
                };
                self.variable_ctx.variable_map.insert(p.clone(), pid);
                // Phase 136 Step 3/7: Insert into scope_ctx (SSOT)
                self.scope_ctx.function_param_names.insert(p.clone());

                // Phase 26-A-3: パラメータ型情報を収集（後で一括登録）
                // param_idx: receiver offset を考慮した実際のパラメータインデックス
                param_kinds.push((pid, param_idx as u32));

                let ty = param_types.get(param_idx).cloned();
                slot_regs.push((p.clone(), ty));
            }
        }

        // Phase 26-A-3: パラメータ型情報を一括登録（GUARD Bug Prevention）
        for (pid, param_idx) in param_kinds {
            self.register_value_kind(pid, MirValueKind::Parameter(param_idx));
        }

        if let Some(reg) = self.comp_ctx.current_slot_registry.as_mut() {
            for (name, ty) in slot_regs {
                reg.ensure_slot(&name, ty);
            }
        }
    }

    /// 🎯 箱理論: Step 4 - 本体lowering
    fn lower_function_body(&mut self, body: Vec<ASTNode>) -> Result<(), String> {
        let trace = crate::mir::builder::control_flow::joinir::trace::trace();

        // Phase 112: StepTree capability guard (strict-only) + dev shadow lowering
        let strict = crate::config::env::joinir_dev::strict_enabled();
        let dev = crate::config::env::joinir_dev_enabled();
        let func_name = self
            .scope_ctx
            .current_function
            .as_ref()
            .map(|f| f.signature.name.clone())
            .unwrap_or_else(|| "<unknown>".to_string());

        struct JoinLoopTraceDevAdapter<'a> {
            trace: &'a crate::mir::builder::control_flow::joinir::trace::JoinLoopTrace,
        }
        impl crate::mir::control_tree::normalized_shadow::dev_pipeline::DevTrace
            for JoinLoopTraceDevAdapter<'_>
        {
            fn dev(&self, tag: &str, msg: &str) {
                self.trace.dev(tag, msg)
            }
        }
        let trace_adapter = JoinLoopTraceDevAdapter { trace: &trace };

        crate::mir::control_tree::normalized_shadow::dev_pipeline::StepTreeDevPipelineBox::run(
            self,
            &body,
            &func_name,
            strict,
            dev,
            &trace_adapter,
        )?;

        trace.emit_if(
            "debug",
            "lower_function_body",
            &format!("body.len() = {}", body.len()),
            trace.is_enabled(),
        );

        let program_ast = function_lowering::wrap_in_program(body);
        trace.emit_if(
            "debug",
            "lower_function_body",
            "About to call build_expression",
            trace.is_enabled(),
        );
        let _last = self.build_expression(program_ast)?;
        trace.emit_if(
            "debug",
            "lower_function_body",
            "build_expression completed",
            trace.is_enabled(),
        );
        Ok(())
    }

    /// 🎯 箱理論: Step 5 - 関数finalize
    #[allow(deprecated)]
    fn finalize_function(&mut self, returns_value: bool) -> Result<(), String> {
        // Void return追加（必要な場合）
        if !returns_value {
            if let Some(ref mut f) = self.scope_ctx.current_function {
                if let Some(block) = f.get_block(self.current_block.unwrap()) {
                    if !block.is_terminated() {
                        let void_val = crate::mir::builder::emission::constant::emit_void(self);
                        self.emit_instruction(MirInstruction::Return {
                            value: Some(void_val),
                        })?;
                    }
                }
            }
        }

        // 型推論
        if let Some(ref mut f) = self.scope_ctx.current_function {
            if returns_value && matches!(f.signature.return_type, MirType::Void | MirType::Unknown)
            {
                let mut inferred: Option<MirType> = None;
                'search: for (_bid, bb) in f.blocks.iter() {
                    for inst in bb.instructions.iter() {
                        if let MirInstruction::Return { value: Some(v) } = inst {
                            if let Some(mt) = self.type_ctx.value_types.get(v).cloned() {
                                inferred = Some(mt);
                                break 'search;
                            }
                        }
                    }
                    if let Some(MirInstruction::Return { value: Some(v) }) = &bb.terminator {
                        if let Some(mt) = self.type_ctx.value_types.get(v).cloned() {
                            inferred = Some(mt);
                            break;
                        }
                    }
                }
                if let Some(mt) = inferred {
                    f.signature.return_type = mt;
                }
            }
        }

        // Moduleに追加
        // Phase 136 Step 3/7: Take from scope_ctx (SSOT)
        let finalized = self.scope_ctx.current_function.take().unwrap();
        if let Some(ref mut module) = self.current_module {
            module.add_function(finalized);
        }

        Ok(())
    }

    /// 🎯 箱理論: Step 6 - Context復元
    fn restore_lowering_context(&mut self, ctx: LoweringContext) {
        // Phase 136 Step 3/7: Restore to scope_ctx (SSOT)
        self.scope_ctx.current_function = ctx.saved_function;
        self.current_block = ctx.saved_block;

        // モード別にcontext復元
        if ctx.context_active {
            // BoxCompilationContext mode: clear のみ（次回も完全独立）
            self.variable_ctx.variable_map.clear();
            self.type_ctx.value_origin_newbox.clear();
            // static box ごとに型情報も独立させる（前 box の型メタデータを引きずらない）
            self.type_ctx.value_types.clear();
        } else if let Some(saved) = ctx.saved_var_map {
            // Legacy mode: Main.main 側の variable_map を元に戻す
            self.variable_ctx.variable_map = saved;
        }

        // Static box context復元
        self.comp_ctx.current_static_box = ctx.saved_static_ctx;
        // 関数スコープ SlotRegistry も元の関数に戻すよ。
        self.comp_ctx.current_slot_registry = ctx.saved_slot_registry;
    }

    /// 🎯 箱理論: Step 2b - 関数スケルトン作成（instance method版）
    fn create_method_skeleton(
        &mut self,
        func_name: String,
        box_name: &str,
        params: &[String],
        body: &[ASTNode],
        ctx: &mut LoweringContext,
    ) -> Result<(), String> {
        let signature =
            function_lowering::prepare_method_signature(func_name, box_name, params, body);
        let entry = self.next_block_id();
        let function = self.new_function_with_metadata(signature, entry);

        // Phase 136 Step 3/7: Save from scope_ctx (SSOT)
        ctx.saved_function = self.scope_ctx.current_function.take();
        ctx.saved_block = self.current_block.take();

        // Phase 136 Step 3/7: Use scope_ctx as SSOT
        self.scope_ctx.current_function = Some(function);
        self.current_block = Some(entry);
        // instance method 用の関数スコープ SlotRegistry もここで用意するよ。
        self.comp_ctx.current_slot_registry = Some(FunctionSlotRegistry::new());
        self.ensure_block_exists(entry)?;

        // Region 観測レイヤ: instance method 用の FunctionRegion も積んでおくよ。
        crate::mir::region::observer::observe_function_region(self);

        Ok(())
    }

    /// 🎯 箱理論: Step 3b - パラメータ設定（instance method版: me + params）
    fn setup_method_params(&mut self, box_name: &str, params: &[String]) {
        // SlotRegistry 更新はローカルバッファに集約してから反映するよ。
        let mut slot_regs: Vec<(String, Option<MirType>)> = Vec::new();

        if let Some(ref mut f) = self.scope_ctx.current_function {
            // 📦 Hotfix 6 改訂版:
            // MirFunction::new() が既に 0..N の ValueId を params 用に予約しているので、
            // ここではそれを「上書き使用」するだけにして、push で二重定義しないようにするよ。
            //
            // params レイアウト:
            //   index 0: me (box<MyBox>)
            //   index 1..: 通常パラメータ
            if f.params.is_empty() {
                // 安全弁: 何らかの理由で pre-populate されていない場合は従来どおり new する
                let me_id = ValueId(0);
                f.params.push(me_id);
                for i in 0..params.len() {
                    f.params.push(ValueId((i + 1) as u32));
                }
            }

            // me
            let me_id = f.params[0];
            self.variable_ctx
                .variable_map
                .insert("me".to_string(), me_id);
            self.type_ctx
                .value_origin_newbox
                .insert(me_id, box_name.to_string());
            slot_regs.push(("me".to_string(), None));

            // 通常パラメータ
            for (idx, p) in params.iter().enumerate() {
                let param_idx = idx + 1;
                if param_idx < f.params.len() {
                    let pid = f.params[param_idx];
                    self.variable_ctx.variable_map.insert(p.clone(), pid);
                    slot_regs.push((p.clone(), None));
                } else {
                    // 念のため足りない場合は新規に確保（互換用）
                    let pid = f.next_value_id();
                    f.params.push(pid);
                    self.variable_ctx.variable_map.insert(p.clone(), pid);
                    slot_regs.push((p.clone(), None));
                }
            }
        }

        if let Some(reg) = self.comp_ctx.current_slot_registry.as_mut() {
            for (name, ty) in slot_regs {
                reg.ensure_slot(&name, ty);
            }
        }
    }

    /// 🎯 箱理論: Step 4b - 本体lowering（instance method版: cf_block）
    fn lower_method_body(&mut self, body: Vec<ASTNode>) -> Result<(), String> {
        let _last = self.cf_block(body)?;
        Ok(())
    }

    /// 🎯 箱理論: 統合エントリーポイント - static method lowering
    pub(in crate::mir::builder) fn lower_static_method_as_function(
        &mut self,
        func_name: String,
        params: Vec<String>,
        body: Vec<ASTNode>,
    ) -> Result<(), String> {
        // Phase 200-C: Store fn_body for capture analysis
        eprintln!(
            "[lower_static_method_as_function] Storing fn_body with {} nodes for '{}'",
            body.len(),
            func_name
        );
        self.comp_ctx.fn_body_ast = Some(body.clone());

        // Step 1: Context準備
        let mut ctx = self.prepare_lowering_context(&func_name);

        // Step 2: 関数スケルトン作成
        self.create_function_skeleton(func_name, &params, &body, &mut ctx)?;

        // Step 3: パラメータ設定
        self.setup_function_params(&params);

        // Step 4: 本体lowering
        self.lower_function_body(body)?;

        // Step 5: 関数finalize
        let returns_value = if let Some(ref f) = self.scope_ctx.current_function {
            !matches!(f.signature.return_type, MirType::Void)
        } else {
            false
        };
        self.finalize_function(returns_value)?;

        // FunctionRegion を 1 段ポップして元の関数コンテキストに戻るよ。
        crate::mir::region::observer::pop_function_region(self);

        // Step 6: Context復元
        self.restore_lowering_context(ctx);

        // Phase 200-C: Clear fn_body_ast after function lowering
        self.comp_ctx.fn_body_ast = None;

        Ok(())
    }

    /// 🎯 箱理論: 統合エントリーポイント - instance method lowering
    pub(in crate::mir::builder) fn lower_method_as_function(
        &mut self,
        func_name: String,
        box_name: String,
        params: Vec<String>,
        body: Vec<ASTNode>,
    ) -> Result<(), String> {
        // Phase 200-C: Store fn_body for capture analysis
        self.comp_ctx.fn_body_ast = Some(body.clone());

        // Step 1: Context準備（instance methodでは不要だがAPI統一のため）
        let mut ctx = LoweringContext {
            context_active: false,
            saved_var_map: Some(std::mem::take(&mut self.variable_ctx.variable_map)),
            saved_static_ctx: None,
            saved_function: None,
            saved_block: None,
            saved_slot_registry: self.comp_ctx.current_slot_registry.take(),
        };

        // Step 2b: 関数スケルトン作成（method版）
        self.create_method_skeleton(func_name, &box_name, &params, &body, &mut ctx)?;

        // Step 3b: パラメータ設定（me + params）
        self.setup_method_params(&box_name, &params);

        // Step 4b: 本体lowering（cf_block版）
        self.lower_method_body(body)?;

        // Step 5: 関数finalize
        let returns_value = if let Some(ref f) = self.scope_ctx.current_function {
            !matches!(f.signature.return_type, MirType::Void)
        } else {
            false
        };

        // Void return追加（必要な場合）
        if !returns_value && !self.is_current_block_terminated() {
            let void_val = crate::mir::builder::emission::constant::emit_void(self);
            self.emit_instruction(MirInstruction::Return {
                value: Some(void_val),
            })?;
        }

        // 型推論（Step 5の一部として）
        if let Some(ref mut f) = self.scope_ctx.current_function {
            if returns_value && matches!(f.signature.return_type, MirType::Void | MirType::Unknown)
            {
                let mut inferred: Option<MirType> = None;
                'search: for (_bid, bb) in f.blocks.iter() {
                    for inst in bb.instructions.iter() {
                        if let MirInstruction::Return { value: Some(v) } = inst {
                            if let Some(mt) = self.type_ctx.value_types.get(v).cloned() {
                                inferred = Some(mt);
                                break 'search;
                            }
                        }
                    }
                    if let Some(MirInstruction::Return { value: Some(v) }) = &bb.terminator {
                        if let Some(mt) = self.type_ctx.value_types.get(v).cloned() {
                            inferred = Some(mt);
                            break;
                        }
                    }
                }
                if let Some(mt) = inferred {
                    f.signature.return_type = mt;
                }
            }
        }

        // Moduleに追加
        let finalized_function = self.scope_ctx.current_function.take().unwrap();
        if let Some(ref mut module) = self.current_module {
            module.add_function(finalized_function);
        }

        // FunctionRegion を 1 段ポップして元の関数コンテキストに戻るよ。
        crate::mir::region::observer::pop_function_region(self);

        // Phase 136 Step 3/7: Restore to scope_ctx (SSOT)
        self.scope_ctx.current_function = ctx.saved_function;
        self.current_block = ctx.saved_block;
        if let Some(saved) = ctx.saved_var_map {
            self.variable_ctx.variable_map = saved;
        }
        self.comp_ctx.current_slot_registry = ctx.saved_slot_registry;

        // Phase 200-C: Clear fn_body_ast after function lowering
        self.comp_ctx.fn_body_ast = None;

        Ok(())
    }
}
