use super::convert::convert_mir_like_inst;
use super::*;
use crate::mir::join_ir::frontend::AstToJoinIrLowerer;
use crate::mir::join_ir_ops::JoinValue;
use crate::mir::{BinaryOp, CompareOp as MirCompareOp, MirInstruction, ValueId};

#[test]
fn test_convert_const_inst() {
    let join_const = crate::mir::join_ir::MirLikeInst::Const {
        dst: ValueId(10),
        value: crate::mir::join_ir::ConstValue::Integer(42),
    };

    let mir_inst = convert_mir_like_inst(&join_const).unwrap();

    match mir_inst {
        MirInstruction::Const { dst, value } => {
            assert_eq!(dst, ValueId(10));
            assert!(matches!(value, crate::mir::ConstValue::Integer(42)));
        }
        _ => panic!("Expected Const instruction"),
    }
}

#[test]
fn test_convert_binop_inst() {
    let join_binop = crate::mir::join_ir::MirLikeInst::BinOp {
        dst: ValueId(20),
        op: crate::mir::join_ir::BinOpKind::Add,
        lhs: ValueId(10),
        rhs: ValueId(11),
    };

    let mir_inst = convert_mir_like_inst(&join_binop).unwrap();

    match mir_inst {
        MirInstruction::BinOp { dst, op, lhs, rhs } => {
            assert_eq!(dst, ValueId(20));
            assert_eq!(op, BinaryOp::Add);
            assert_eq!(lhs, ValueId(10));
            assert_eq!(rhs, ValueId(11));
        }
        _ => panic!("Expected BinOp instruction"),
    }
}

#[test]
fn test_convert_compare_inst() {
    let join_cmp = crate::mir::join_ir::MirLikeInst::Compare {
        dst: ValueId(30),
        op: crate::mir::join_ir::CompareOp::Ge,
        lhs: ValueId(10),
        rhs: ValueId(11),
    };

    let mir_inst = convert_mir_like_inst(&join_cmp).unwrap();

    match mir_inst {
        MirInstruction::Compare { dst, op, lhs, rhs } => {
            assert_eq!(dst, ValueId(30));
            assert_eq!(op, MirCompareOp::Ge);
            assert_eq!(lhs, ValueId(10));
            assert_eq!(rhs, ValueId(11));
        }
        _ => panic!("Expected Compare instruction"),
    }
}

// ========================================
// Phase 45: read_quoted_from Bridge Tests
// ========================================

/// Phase 45: read_quoted_from JoinIR → MIR 変換テスト
///
/// HAKO_JOINIR_READ_QUOTED=1 が設定されている場合のみ実行。
#[test]
fn test_read_quoted_from_joinir_to_mir_conversion() {
    // Dev flag がない場合はスキップ
    if std::env::var("HAKO_JOINIR_READ_QUOTED").ok().as_deref() != Some("1") {
        eprintln!(
            "[Phase 45] Skipping test_read_quoted_from_joinir_to_mir_conversion: \
             Set HAKO_JOINIR_READ_QUOTED=1 to enable"
        );
        return;
    }

    // 1. JoinModule を生成（lower_read_quoted_pattern を使用）
    let program_json = serde_json::json!({
        "defs": [{
            "name": "read_quoted_from",
            "params": ["s", "pos"],
            "body": { "body": [] }
        }]
    });

    let mut lowerer = AstToJoinIrLowerer::new();
    let join_module = lowerer.lower_read_quoted_pattern(&program_json);

    // 2. JoinIR → MIR 変換
    let mir_module = convert_joinir_to_mir(&join_module);

    assert!(
        mir_module.is_ok(),
        "JoinIR → MIR conversion should succeed: {:?}",
        mir_module.err()
    );

    let mir_module = mir_module.unwrap();

    // 3. MIR 構造の検証
    // 4 つの関数がある: entry, k_guard_fail, loop_step, k_exit
    assert_eq!(mir_module.functions.len(), 4, "MIR should have 4 functions");

    // 関数名を確認
    let func_names: Vec<&str> = mir_module.functions.keys().map(|s| s.as_str()).collect();
    eprintln!("[Phase 45] MIR function names: {:?}", func_names);

    // join_func_0 (entry), join_func_1 (loop_step), join_func_2 (k_exit), join_func_3 (k_guard_fail)
    assert!(
        func_names.contains(&"join_func_0"),
        "Should have entry function join_func_0"
    );
    assert!(
        func_names.contains(&"join_func_1"),
        "Should have loop_step function join_func_1"
    );
    assert!(
        func_names.contains(&"join_func_2"),
        "Should have k_exit function join_func_2"
    );
    assert!(
        func_names.contains(&"join_func_3"),
        "Should have k_guard_fail function join_func_3"
    );

    eprintln!("[Phase 45] test_read_quoted_from_joinir_to_mir_conversion PASSED");
}

/// Phase 45: String 定数の MIR 変換テスト
#[test]
fn test_convert_string_const_inst() {
    let join_const = crate::mir::join_ir::MirLikeInst::Const {
        dst: ValueId(50),
        value: crate::mir::join_ir::ConstValue::String("\"".to_string()),
    };

    let mir_inst = convert_mir_like_inst(&join_const).unwrap();

    match mir_inst {
        MirInstruction::Const { dst, value } => {
            assert_eq!(dst, ValueId(50));
            match value {
                crate::mir::ConstValue::String(s) => assert_eq!(s, "\""),
                _ => panic!("Expected String value"),
            }
        }
        _ => panic!("Expected Const instruction"),
    }
}

/// Phase 45: A/B テスト - Route B (JoinIR) E2E 実行テスト
///
/// HAKO_JOINIR_READ_QUOTED=1 が設定されている場合のみ実行。
///
/// # Test Cases (from Phase 45 fixture)
///
/// - T1: `"abc"` at pos 0 → `abc`
/// - T2: `""` at pos 0 → `` (empty)
/// - T3: `abc` at pos 0 → `` (guard fail, no quote)
/// - T4: `xx"def"` at pos 2 → `def`
///
/// # Known Limitation
///
/// T5 (escape handling) is skipped due to known PHI issue
/// with variable reassignment inside if-blocks.
#[test]
fn test_read_quoted_from_route_b_e2e() {
    // Dev flag がない場合はスキップ
    if std::env::var("HAKO_JOINIR_READ_QUOTED").ok().as_deref() != Some("1") {
        eprintln!(
            "[Phase 45] Skipping test_read_quoted_from_route_b_e2e: \
             Set HAKO_JOINIR_READ_QUOTED=1 to enable"
        );
        return;
    }

    // 1. JoinModule を生成
    let program_json = serde_json::json!({
        "defs": [{
            "name": "read_quoted_from",
            "params": ["s", "pos"],
            "body": { "body": [] }
        }]
    });

    let mut lowerer = AstToJoinIrLowerer::new();
    let join_module = lowerer.lower_read_quoted_pattern(&program_json);

    let entry_func = join_module.entry.expect("Entry function should exist");

    // 2. A/B テスト実行
    // Note: Route B (JoinIR) は run_joinir_via_vm で実行
    //       Route A (既存) は別途フィクスチャで検証済み

    // T1: "abc" at pos 0 → "abc"
    let t1_result = run_joinir_via_vm(
        &join_module,
        entry_func,
        &[JoinValue::Str("\"abc\"".to_string()), JoinValue::Int(0)],
    );
    match &t1_result {
        Ok(JoinValue::Str(s)) => {
            assert_eq!(s, "abc", "T1: Expected 'abc', got '{}'", s);
            eprintln!("[Phase 45] T1 PASS: \"abc\" at pos 0 → '{}'", s);
        }
        Ok(v) => panic!("T1: Expected Str, got {:?}", v),
        Err(e) => eprintln!("[Phase 45] T1 SKIP (execution not supported): {:?}", e),
    }

    // T2: "" at pos 0 → "" (empty)
    let t2_result = run_joinir_via_vm(
        &join_module,
        entry_func,
        &[JoinValue::Str("\"\"".to_string()), JoinValue::Int(0)],
    );
    match &t2_result {
        Ok(JoinValue::Str(s)) => {
            assert_eq!(s, "", "T2: Expected '', got '{}'", s);
            eprintln!("[Phase 45] T2 PASS: \"\" at pos 0 → '{}'", s);
        }
        Ok(v) => panic!("T2: Expected Str, got {:?}", v),
        Err(e) => eprintln!("[Phase 45] T2 SKIP (execution not supported): {:?}", e),
    }

    // T3: abc at pos 0 → "" (guard fail)
    let t3_result = run_joinir_via_vm(
        &join_module,
        entry_func,
        &[JoinValue::Str("abc".to_string()), JoinValue::Int(0)],
    );
    match &t3_result {
        Ok(JoinValue::Str(s)) => {
            assert_eq!(s, "", "T3: Expected '', got '{}'", s);
            eprintln!("[Phase 45] T3 PASS: abc at pos 0 → '{}'", s);
        }
        Ok(v) => panic!("T3: Expected Str, got {:?}", v),
        Err(e) => eprintln!("[Phase 45] T3 SKIP (execution not supported): {:?}", e),
    }

    // T4: xx"def" at pos 2 → "def"
    let t4_result = run_joinir_via_vm(
        &join_module,
        entry_func,
        &[JoinValue::Str("xx\"def\"".to_string()), JoinValue::Int(2)],
    );
    match &t4_result {
        Ok(JoinValue::Str(s)) => {
            assert_eq!(s, "def", "T4: Expected 'def', got '{}'", s);
            eprintln!("[Phase 45] T4 PASS: xx\"def\" at pos 2 → '{}'", s);
        }
        Ok(v) => panic!("T4: Expected Str, got {:?}", v),
        Err(e) => eprintln!("[Phase 45] T4 SKIP (execution not supported): {:?}", e),
    }

    // T5: Escape handling - "a\"b" at pos 0 → "a"b" (escaped quote)
    // Phase 46: IfMerge で if-body 後の i と ch をマージ
    let enable_escape_ifmerge = std::env::var("HAKO_JOINIR_READ_QUOTED_IFMERGE")
        .ok()
        .as_deref()
        == Some("1");

    if enable_escape_ifmerge {
        // 入力: "a\"b" → 「"」で始まり、a, \", b, 「"」で終わる
        // 期待出力: a"b（エスケープされた引用符を含む）
        let t5_input = "\"a\\\"b\""; // Rust エスケープ: "a\"b" → JSON "a\"b"
        let t5_result = run_joinir_via_vm(
            &join_module,
            entry_func,
            &[JoinValue::Str(t5_input.to_string()), JoinValue::Int(0)],
        );
        match &t5_result {
            Ok(JoinValue::Str(s)) => {
                let expected = "a\"b"; // エスケープ後: a"b
                assert_eq!(s, expected, "T5: Expected '{}', got '{}'", expected, s);
                eprintln!(
                    "[Phase 46] T5 PASS: \"a\\\"b\" at pos 0 → '{}' (escape handling works!)",
                    s
                );
            }
            Ok(v) => panic!("T5: Expected Str, got {:?}", v),
            Err(e) => eprintln!("[Phase 46] T5 SKIP (execution not supported): {:?}", e),
        }
    } else {
        eprintln!(
            "[Phase 45] T5 SKIP: Set HAKO_JOINIR_READ_QUOTED_IFMERGE=1 to enable \
             escape handling (Phase 46)"
        );
    }

    eprintln!("[Phase 45] test_read_quoted_from_route_b_e2e completed");
}
