use super::{convert_join_module_to_mir_with_meta, JoinIrVmBridgeError};
use crate::mir::join_ir::frontend::JoinFuncMetaMap;
use crate::mir::join_ir::JoinModule;
use crate::mir::MirModule;
use std::collections::BTreeMap;

#[cfg(feature = "normalized_dev")]
use crate::config::env::joinir_dev::{current_joinir_mode, JoinIrMode};
#[cfg(feature = "normalized_dev")]
use crate::mir::join_ir::normalized::shape_guard::{self, NormalizedDevShape};
#[cfg(feature = "normalized_dev")]
use crate::mir::join_ir::normalized::{
    normalize_pattern1_minimal, normalize_pattern2_minimal, NormalizedModule,
};
#[cfg(feature = "normalized_dev")]
use crate::mir::join_ir::JoinIrPhase;
#[cfg(feature = "normalized_dev")]
use crate::mir::join_ir_vm_bridge::lower_normalized_to_mir_minimal;
#[cfg(feature = "normalized_dev")]
use std::panic::{catch_unwind, AssertUnwindSafe};

/// Structured JoinIR → MIR（既存経路）の明示エントリ。
pub(crate) fn lower_joinir_structured_to_mir_with_meta(
    module: &JoinModule,
    meta: &JoinFuncMetaMap,
) -> Result<MirModule, JoinIrVmBridgeError> {
    if !module.is_structured() {
        return Err(JoinIrVmBridgeError::new(
            "[joinir/bridge] expected Structured JoinIR module",
        ));
    }

    convert_join_module_to_mir_with_meta(module, meta)
}

/// Normalized JoinIR → MIR（現状は Structured に戻して既存ブリッジを再利用）。
#[cfg(feature = "normalized_dev")]
#[allow(dead_code)]
pub(crate) fn lower_joinir_normalized_to_mir_with_meta(
    module: &NormalizedModule,
    meta: &JoinFuncMetaMap,
) -> Result<MirModule, JoinIrVmBridgeError> {
    if module.phase != JoinIrPhase::Normalized {
        return Err(JoinIrVmBridgeError::new(
            "[joinir/bridge] expected Normalized JoinIR module",
        ));
    }

    let structured = module.to_structured().ok_or_else(|| {
        JoinIrVmBridgeError::new(
            "[joinir/bridge] normalized module missing Structured snapshot (dev-only)",
        )
    })?;

    lower_joinir_structured_to_mir_with_meta(&structured, meta)
}

#[cfg(feature = "normalized_dev")]
fn normalize_for_shape(
    module: &JoinModule,
    shape: NormalizedDevShape,
) -> Result<NormalizedModule, JoinIrVmBridgeError> {
    let result = match shape {
        NormalizedDevShape::Pattern1Mini => {
            catch_unwind(AssertUnwindSafe(|| normalize_pattern1_minimal(module)))
        }
        NormalizedDevShape::Pattern2Mini
        | NormalizedDevShape::JsonparserSkipWsMini
        | NormalizedDevShape::JsonparserSkipWsReal
        | NormalizedDevShape::JsonparserAtoiMini
        | NormalizedDevShape::JsonparserAtoiReal
        | NormalizedDevShape::JsonparserParseNumberReal => {
            catch_unwind(AssertUnwindSafe(|| normalize_pattern2_minimal(module)))
        }
        NormalizedDevShape::SelfhostTokenScanP2 => catch_unwind(AssertUnwindSafe(|| {
            crate::mir::join_ir::normalized::normalize_selfhost_token_scan_p2(module)
                .expect("selfhost P2 normalization failed")
        })),
        NormalizedDevShape::SelfhostTokenScanP2Accum => catch_unwind(AssertUnwindSafe(|| {
            crate::mir::join_ir::normalized::normalize_selfhost_token_scan_p2_accum(module)
                .expect("selfhost P2 accum normalization failed")
        })),
        // Phase 47-A: P3 minimal normalization
        NormalizedDevShape::Pattern3IfSumMinimal => catch_unwind(AssertUnwindSafe(|| {
            crate::mir::join_ir::normalized::normalize_pattern3_if_sum_minimal(module)
                .expect("P3 normalization failed")
        })),
        // Phase 47-B: P3 extended normalization
        NormalizedDevShape::Pattern3IfSumMulti => catch_unwind(AssertUnwindSafe(|| {
            crate::mir::join_ir::normalized::normalize_pattern3_if_sum_multi_minimal(module)
                .expect("P3 multi normalization failed")
        })),
        NormalizedDevShape::Pattern3IfSumJson => catch_unwind(AssertUnwindSafe(|| {
            crate::mir::join_ir::normalized::normalize_pattern3_if_sum_json_minimal(module)
                .expect("P3 json normalization failed")
        })),
        NormalizedDevShape::SelfhostIfSumP3 => catch_unwind(AssertUnwindSafe(|| {
            crate::mir::join_ir::normalized::normalize_selfhost_if_sum_p3(module)
                .expect("selfhost P3 normalization failed")
        })),
        NormalizedDevShape::SelfhostIfSumP3Ext => catch_unwind(AssertUnwindSafe(|| {
            crate::mir::join_ir::normalized::normalize_selfhost_if_sum_p3_ext(module)
                .expect("selfhost P3 ext normalization failed")
        })),
        // Phase 53: selfhost P2/P3 practical variations (delegate to existing normalizers)
        NormalizedDevShape::SelfhostArgsParseP2 => {
            catch_unwind(AssertUnwindSafe(|| normalize_pattern2_minimal(module)))
        }
        NormalizedDevShape::SelfhostStmtCountP3 => catch_unwind(AssertUnwindSafe(|| {
            crate::mir::join_ir::normalized::normalize_selfhost_if_sum_p3_ext(module)
                .expect("selfhost stmt_count P3 normalization failed")
        })),
        // Phase 54: selfhost P2/P3 shape growth (delegate to existing normalizers)
        NormalizedDevShape::SelfhostVerifySchemaP2 => {
            catch_unwind(AssertUnwindSafe(|| normalize_pattern2_minimal(module)))
        }
        NormalizedDevShape::SelfhostDetectFormatP3 => catch_unwind(AssertUnwindSafe(|| {
            crate::mir::join_ir::normalized::normalize_selfhost_if_sum_p3_ext(module)
                .expect("selfhost detect_format P3 normalization failed")
        })),
        // Phase 48-A: P4 minimal normalization
        NormalizedDevShape::Pattern4ContinueMinimal => catch_unwind(AssertUnwindSafe(|| {
            crate::mir::join_ir::normalized::normalize_pattern4_continue_minimal(module)
                .expect("P4 normalization failed")
        })),
        // Phase 48-B: JsonParser continue skip_ws (array/object)
        NormalizedDevShape::JsonparserParseArrayContinueSkipWs => {
            catch_unwind(AssertUnwindSafe(|| {
                crate::mir::join_ir::normalized::normalize_jsonparser_parse_array_continue_skip_ws(
                    module,
                )
                .expect("P4 array normalization failed")
            }))
        }
        NormalizedDevShape::JsonparserParseObjectContinueSkipWs => {
            catch_unwind(AssertUnwindSafe(|| {
                crate::mir::join_ir::normalized::normalize_jsonparser_parse_object_continue_skip_ws(
                    module,
                )
                .expect("P4 object normalization failed")
            }))
        }
        // Phase 89: Continue + Early Return pattern (dev-only, delegates to P2 for now)
        NormalizedDevShape::PatternContinueReturnMinimal => {
            catch_unwind(AssertUnwindSafe(|| normalize_pattern2_minimal(module)))
        }
        // Phase 90: Parse String Composite pattern (dev-only, delegates to P2 for now)
        NormalizedDevShape::ParseStringCompositeMinimal => {
            catch_unwind(AssertUnwindSafe(|| normalize_pattern2_minimal(module)))
        }
    };

    match result {
        Ok(norm) => Ok(norm),
        Err(_) => Err(JoinIrVmBridgeError::new(format!(
            "[joinir/bridge/normalized] normalization failed for shape {:?}",
            shape
        ))),
    }
}

#[cfg(feature = "normalized_dev")]
fn try_normalized_direct_bridge(
    module: &JoinModule,
    meta: &JoinFuncMetaMap,
    shapes: &[NormalizedDevShape],
    allow_structured_fallback: bool,
    use_env_guard: bool,
) -> Result<Option<MirModule>, JoinIrVmBridgeError> {
    if shapes.is_empty() {
        crate::mir::join_ir_vm_bridge::normalized_bridge::log_dev(
            "fallback",
            "normalized dev enabled but shape unsupported; using Structured path",
            true,
        );
        return if allow_structured_fallback {
            Ok(None)
        } else {
            Err(JoinIrVmBridgeError::new(
                "[joinir/bridge] canonical normalized route requested but shape unsupported",
            ))
        };
    }

    let exec = || {
        let debug = crate::mir::join_ir::normalized::dev_env::normalized_dev_logs_enabled();
        for &shape in shapes {
            if debug {
                crate::mir::join_ir_vm_bridge::normalized_bridge::log_dev(
                    "direct",
                    format!("attempting normalized→MIR for {:?}", shape),
                    false,
                );
            }
            match normalize_for_shape(module, shape) {
                Ok(norm) => {
                    let mir =
                        lower_normalized_to_mir_minimal(&norm, meta, allow_structured_fallback)?;
                    crate::mir::join_ir_vm_bridge::normalized_bridge::log_dev(
                        "direct",
                        format!(
                            "normalized→MIR succeeded (shape={:?}, functions={})",
                            shape,
                            norm.functions.len()
                        ),
                        false,
                    );
                    return Ok(Some(mir));
                }
                Err(err) => {
                    if debug {
                        crate::mir::join_ir_vm_bridge::normalized_bridge::log_dev(
                            "direct",
                            format!(
                                "{:?} normalization failed: {} (continuing)",
                                shape, err.message
                            ),
                            false,
                        );
                    }
                }
            }
        }

        if allow_structured_fallback {
            Ok(None)
        } else {
            Err(JoinIrVmBridgeError::new(
                "[joinir/bridge] canonical normalized route failed for all shapes",
            ))
        }
    };

    if use_env_guard {
        crate::mir::join_ir::normalized::dev_env::with_dev_env_if_unset(exec)
    } else {
        exec()
    }
}

/// JoinIR → MIR の単一入口。Mode に応じて Normalized/Structured 経路を選択。
///
/// Phase 45: JoinIrMode 導入による統一ルーティング:
/// - Canonical P2-Core shapes → 常に Normalized→MIR(direct)（mode 無視）
/// - NormalizedDev → サポート形状のみ Normalized path、それ以外 Structured path
/// - StructuredOnly | NormalizedCanonical → Structured path
pub(crate) fn bridge_joinir_to_mir_with_meta(
    module: &JoinModule,
    meta: &JoinFuncMetaMap,
) -> Result<MirModule, JoinIrVmBridgeError> {
    #[cfg(feature = "normalized_dev")]
    {
        let mode = current_joinir_mode();

        // Canonical set (P2/P3/P4): Always uses Normalized→MIR(direct) regardless of mode/env
        let canonical_shapes = shape_guard::canonical_shapes(module);
        if !canonical_shapes.is_empty() {
            match try_normalized_direct_bridge(module, meta, &canonical_shapes, false, false)? {
                Some(mir) => return Ok(mir),
                None => {
                    return Err(JoinIrVmBridgeError::new(
                        "[joinir/bridge] canonical normalized route returned None unexpectedly",
                    ))
                }
            }
        }

        // Phase 45: Mode によるルーティング分岐
        match mode {
            JoinIrMode::NormalizedDev => {
                // サポート形状のみ Normalized path を試行、失敗時は Structured fallback
                let shapes = shape_guard::direct_shapes(module);
                match try_normalized_direct_bridge(module, meta, &shapes, true, true)? {
                    Some(mir) => return Ok(mir),
                    None => {} // Fallback to Structured
                }
            }
            JoinIrMode::StructuredOnly | JoinIrMode::NormalizedCanonical => {
                // Structured path のみ使用
                // （NormalizedCanonical は将来 Phase 46+ で canonical migration 完了後に専用経路を持つ）
            }
        }
    }

    lower_joinir_structured_to_mir_with_meta(module, meta)
}

/// JoinIR → MIR（メタなし）呼び出しのユーティリティ。
pub(crate) fn bridge_joinir_to_mir(module: &JoinModule) -> Result<MirModule, JoinIrVmBridgeError> {
    let empty_meta: JoinFuncMetaMap = BTreeMap::new();
    bridge_joinir_to_mir_with_meta(module, &empty_meta)
}
