//! JNI bridge generation for native LLVM-compiled widget providers on Android
//!
//! Generates Kotlin code that loads the native library and calls the provider function.

use perry_hir::ir::*;
use std::fmt::Write;

/// Emit the JNI bridge Kotlin class for the native provider
pub fn emit_bridge(widget: &WidgetDecl, name: &str, package: &str) -> String {
    let mut out = String::new();

    writeln!(out, "// Auto-generated by Perry compiler — do not edit").unwrap();
    writeln!(out, "package {}", package).unwrap();
    writeln!(out).unwrap();
    writeln!(out, "import android.content.Context").unwrap();
    writeln!(out, "import android.content.SharedPreferences").unwrap();
    writeln!(out, "import org.json.JSONObject").unwrap();
    writeln!(out, "import org.json.JSONArray").unwrap();
    writeln!(out).unwrap();

    writeln!(out, "object {}Bridge {{", name).unwrap();
    writeln!(out, "    init {{").unwrap();
    writeln!(out, "        System.loadLibrary(\"widget_provider\")").unwrap();
    writeln!(out, "    }}").unwrap();
    writeln!(out).unwrap();

    // Native method declarations
    if let Some(ref func_name) = widget.provider_func_name {
        writeln!(out, "    // Native provider function compiled by LLVM").unwrap();
        writeln!(out, "    @JvmStatic").unwrap();
        writeln!(
            out,
            "    private external fun {}(configJson: String): String",
            func_name
        )
        .unwrap();
        writeln!(out).unwrap();
        writeln!(out, "    @JvmStatic").unwrap();
        writeln!(out, "    private external fun perry_runtime_widget_init()").unwrap();
        writeln!(out).unwrap();
    }

    // sharedStorage bridge
    writeln!(out, "    private var appContext: Context? = null").unwrap();
    writeln!(out).unwrap();

    writeln!(
        out,
        "    // Called from native code via JNI for sharedStorage()"
    )
    .unwrap();
    writeln!(out, "    @JvmStatic").unwrap();
    writeln!(out, "    fun sharedStorageGet(key: String): String {{").unwrap();
    writeln!(out, "        val prefs = appContext?.getSharedPreferences(\"perry_shared\", Context.MODE_PRIVATE)").unwrap();
    writeln!(out, "        return prefs?.getString(key, \"\") ?: \"\"").unwrap();
    writeln!(out, "    }}").unwrap();
    writeln!(out).unwrap();

    // Fetch entry function
    writeln!(
        out,
        "    fun fetchEntry(context: Context): {}Entry {{",
        name
    )
    .unwrap();
    writeln!(out, "        appContext = context.applicationContext").unwrap();

    if let Some(ref func_name) = widget.provider_func_name {
        writeln!(out, "        perry_runtime_widget_init()").unwrap();
        writeln!(out).unwrap();

        // Build config JSON from SharedPreferences
        if !widget.config_params.is_empty() {
            writeln!(out, "        val prefs = context.getSharedPreferences(\"perry_widget_config\", Context.MODE_PRIVATE)").unwrap();
            writeln!(out, "        val configObj = JSONObject()").unwrap();
            for param in &widget.config_params {
                match &param.param_type {
                    WidgetConfigParamType::Enum { default, .. } => {
                        writeln!(
                            out,
                            "        configObj.put(\"{}\", prefs.getString(\"{}\", \"{}\"))",
                            param.name, param.name, default
                        )
                        .unwrap();
                    }
                    WidgetConfigParamType::Bool { default } => {
                        writeln!(
                            out,
                            "        configObj.put(\"{}\", prefs.getBoolean(\"{}\", {}))",
                            param.name, param.name, default
                        )
                        .unwrap();
                    }
                    WidgetConfigParamType::String { default } => {
                        writeln!(
                            out,
                            "        configObj.put(\"{}\", prefs.getString(\"{}\", \"{}\"))",
                            param.name, param.name, default
                        )
                        .unwrap();
                    }
                }
            }
            writeln!(out, "        val configJson = configObj.toString()").unwrap();
        } else {
            writeln!(out, "        val configJson = \"{{}}\"").unwrap();
        }

        writeln!(out, "        val resultJson = {}(configJson)", func_name).unwrap();
        writeln!(out, "        return try {{").unwrap();
        writeln!(out, "            val result = JSONObject(resultJson)").unwrap();
        writeln!(
            out,
            "            val entries = result.getJSONArray(\"entries\")"
        )
        .unwrap();
        writeln!(out, "            if (entries.length() > 0) {{").unwrap();
        writeln!(out, "                val entry = entries.getJSONObject(0)").unwrap();
        write!(out, "                {}Entry(", name).unwrap();
        let field_strs: Vec<String> = widget
            .entry_fields
            .iter()
            .map(|(fname, ftype)| match ftype {
                WidgetFieldType::String => {
                    format!("{} = entry.optString(\"{}\", \"\")", fname, fname)
                }
                WidgetFieldType::Number => {
                    format!("{} = entry.optDouble(\"{}\", 0.0)", fname, fname)
                }
                WidgetFieldType::Boolean => {
                    format!("{} = entry.optBoolean(\"{}\", false)", fname, fname)
                }
                _ => format!("{} = entry.optString(\"{}\", \"\")", fname, fname),
            })
            .collect();
        write!(out, "{}", field_strs.join(", ")).unwrap();
        writeln!(out, ")").unwrap();
        writeln!(out, "            }} else {{").unwrap();
        writeln!(out, "                defaultEntry()").unwrap();
        writeln!(out, "            }}").unwrap();
        writeln!(out, "        }} catch (e: Exception) {{").unwrap();
        writeln!(out, "            defaultEntry()").unwrap();
        writeln!(out, "        }}").unwrap();
    } else {
        writeln!(out, "        return defaultEntry()").unwrap();
    }

    writeln!(out, "    }}").unwrap();
    writeln!(out).unwrap();

    // Default entry
    write!(out, "    private fun defaultEntry() = {}Entry(", name).unwrap();
    let defaults: Vec<String> = widget
        .entry_fields
        .iter()
        .map(|(_, ftype)| kotlin_default_value(ftype))
        .collect();
    write!(out, "{}", defaults.join(", ")).unwrap();
    writeln!(out, ")").unwrap();

    writeln!(out, "}}").unwrap();
    out
}

fn kotlin_default_value(field_type: &WidgetFieldType) -> String {
    match field_type {
        WidgetFieldType::String => "\"\"".to_string(),
        WidgetFieldType::Number => "0.0".to_string(),
        WidgetFieldType::Boolean => "false".to_string(),
        WidgetFieldType::Array(_) => "emptyList()".to_string(),
        WidgetFieldType::Optional(_) => "null".to_string(),
        WidgetFieldType::Object(_) => "emptyMap()".to_string(),
    }
}
