use crate::runner;
use serde_json::Value as JsonValue;
use std::collections::BTreeMap;
use std::fs;
// use std::io::Write; // kept for future pretty-print extensions

/// Convert Program(JSON v0) to MIR(JSON v0) and return it as a String.
/// Fail-Fast: prints stable tags on stderr and returns Err with the same tag text.
pub fn program_json_to_mir_json(program_json: &str) -> Result<String, String> {
    program_json_to_mir_json_with_imports(program_json, BTreeMap::new())
}

/// Convert Program(JSON v0) to MIR(JSON v0) with using imports support.
pub fn program_json_to_mir_json_with_imports(
    program_json: &str,
    imports: BTreeMap<String, String>,
) -> Result<String, String> {
    // Basic header check
    if !program_json.contains("\"version\"") || !program_json.contains("\"kind\"") {
        let tag = "[mirbuilder/input/invalid] missing version/kind keys";
        eprintln!("{}", tag);
        return Err(tag.into());
    }

    // Parse Program(JSON v0) into a MIR Module with imports
    let module =
        match runner::json_v0_bridge::parse_json_v0_to_module_with_imports(program_json, imports) {
            Ok(m) => m,
            Err(e) => {
                let tag = format!("[mirbuilder/parse/error] {}", e);
                eprintln!("{}", tag);
                return Err(tag);
            }
        };

    // Emit MIR(JSON) to a temporary file (reuse existing emitter), then read back
    let tmp_dir = std::env::temp_dir();
    let tmp_path = tmp_dir.join("hako_mirbuilder_out.json");
    // Emit MIR JSON (force v1 schema for provider route)
    let prev_v1 = std::env::var("NYASH_JSON_SCHEMA_V1").ok();
    std::env::set_var("NYASH_JSON_SCHEMA_V1", "1");
    let emit_res = runner::mir_json_emit::emit_mir_json_for_harness_bin(&module, &tmp_path);
    // Restore previous env
    match prev_v1 {
        Some(v) => std::env::set_var("NYASH_JSON_SCHEMA_V1", v),
        None => std::env::remove_var("NYASH_JSON_SCHEMA_V1"),
    }
    if let Err(e) = emit_res {
        let tag = format!("[mirbuilder/emit/error] {}", e);
        eprintln!("{}", tag);
        return Err(tag);
    }
    match fs::read_to_string(&tmp_path) {
        Ok(s0) => {
            // Best-effort cleanup
            let _ = fs::remove_file(&tmp_path);
            // Ensure v1 schema: if output lacks schema_version but has functions, wrap minimally
            let s = match serde_json::from_str::<JsonValue>(&s0) {
                Ok(JsonValue::Object(m)) => {
                    if m.get("schema_version").is_none() {
                        if let Some(funcs) = m.get("functions").cloned() {
                            let v1 = serde_json::json!({"schema_version":"1.0","functions": funcs});
                            serde_json::to_string(&v1).unwrap_or(s0)
                        } else {
                            s0
                        }
                    } else {
                        s0
                    }
                }
                _ => s0,
            };
            Ok(s)
        }
        Err(e) => {
            let tag = format!("[mirbuilder/read/error] {}", e);
            eprintln!("{}", tag);
            Err(tag)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_imports_resolution() {
        // Program JSON with MatI64.new(4, 4)
        let program_json = r#"{
            "version": 0,
            "kind": "Program",
            "body": [
                {
                    "type": "Local",
                    "name": "n",
                    "expr": {"type": "Int", "value": 4}
                },
                {
                    "type": "Local",
                    "name": "A",
                    "expr": {
                        "type": "Method",
                        "recv": {"type": "Var", "name": "MatI64"},
                        "method": "new",
                        "args": [
                            {"type": "Var", "name": "n"},
                            {"type": "Var", "name": "n"}
                        ]
                    }
                },
                {
                    "type": "Return",
                    "expr": {
                        "type": "Method",
                        "recv": {"type": "Var", "name": "A"},
                        "method": "at",
                        "args": [
                            {"type": "Int", "value": 0},
                            {"type": "Int", "value": 0}
                        ]
                    }
                }
            ]
        }"#;

        // Create imports map
        let mut imports = BTreeMap::new();
        imports.insert("MatI64".to_string(), "MatI64".to_string());

        // Call with imports
        let result = program_json_to_mir_json_with_imports(program_json, imports);

        // Should succeed
        assert!(result.is_ok(), "Failed with error: {:?}", result.err());

        let mir_json = result.unwrap();
        // MIR JSON should contain functions
        assert!(
            mir_json.contains("functions"),
            "MIR JSON should contain functions"
        );
        eprintln!("[test] MIR JSON generated successfully with MatI64 imports");
    }
}
