use minijinja::Environment;

static TEMPLATES: &[(&str, &str)] = &[
    ("lib_header.rs.jinja", include_str!("templates/lib_header.rs.jinja")),
    (
        "runtime_helpers.rs.jinja",
        include_str!("templates/runtime_helpers.rs.jinja"),
    ),
    (
        "trait_register_shim.rs.jinja",
        include_str!("templates/trait_register_shim.rs.jinja"),
    ),
    (
        "trait_unregister_shim.rs.jinja",
        include_str!("templates/trait_unregister_shim.rs.jinja"),
    ),
    (
        "trait_clear_shim.rs.jinja",
        include_str!("templates/trait_clear_shim.rs.jinja"),
    ),
    (
        "function_shim_open.rs.jinja",
        include_str!("templates/function_shim_open.rs.jinja"),
    ),
    (
        "call_result_body.rs.jinja",
        include_str!("templates/call_result_body.rs.jinja"),
    ),
    (
        "method_shim_open.rs.jinja",
        include_str!("templates/method_shim_open.rs.jinja"),
    ),
    (
        "method_client_handle.rs.jinja",
        include_str!("templates/method_client_handle.rs.jinja"),
    ),
    (
        "streaming_shims.rs.jinja",
        include_str!("templates/streaming_shims.rs.jinja"),
    ),
    (
        "constructor_shim.rs.jinja",
        include_str!("templates/constructor_shim.rs.jinja"),
    ),
    (
        "destructor_shim.rs.jinja",
        include_str!("templates/destructor_shim.rs.jinja"),
    ),
    (
        "service_header.rs.jinja",
        include_str!("templates/service_header.rs.jinja"),
    ),
    (
        "service_opaque.rs.jinja",
        include_str!("templates/service_opaque.rs.jinja"),
    ),
    (
        "handler_bridge_struct.rs.jinja",
        include_str!("templates/handler_bridge_struct.rs.jinja"),
    ),
    (
        "handler_bridge_impl.rs.jinja",
        include_str!("templates/handler_bridge_impl.rs.jinja"),
    ),
    (
        "registration_variant.rs.jinja",
        include_str!("templates/registration_variant.rs.jinja"),
    ),
    (
        "registration_function.rs.jinja",
        include_str!("templates/registration_function.rs.jinja"),
    ),
    (
        "entrypoint_run.rs.jinja",
        include_str!("templates/entrypoint_run.rs.jinja"),
    ),
    (
        "entrypoint_finalize.rs.jinja",
        include_str!("templates/entrypoint_finalize.rs.jinja"),
    ),
    ("param_decl.rs.jinja", include_str!("templates/param_decl.rs.jinja")),
    (
        "service_param_decl.rs.jinja",
        include_str!("templates/service_param_decl.rs.jinja"),
    ),
    (
        "string_unmarshal.rs.jinja",
        include_str!("templates/string_unmarshal.rs.jinja"),
    ),
    (
        "byte_array_unmarshal.rs.jinja",
        include_str!("templates/byte_array_unmarshal.rs.jinja"),
    ),
    (
        "base64_bytes_unmarshal.rs.jinja",
        include_str!("templates/base64_bytes_unmarshal.rs.jinja"),
    ),
    (
        "opaque_handle_unmarshal.rs.jinja",
        include_str!("templates/opaque_handle_unmarshal.rs.jinja"),
    ),
    (
        "complex_unmarshal.rs.jinja",
        include_str!("templates/complex_unmarshal.rs.jinja"),
    ),
    (
        "request_string_unmarshal.rs.jinja",
        include_str!("templates/request_string_unmarshal.rs.jinja"),
    ),
    (
        "request_map_unmarshal.rs.jinja",
        include_str!("templates/request_map_unmarshal.rs.jinja"),
    ),
    (
        "request_map_param_unmarshal.rs.jinja",
        include_str!("templates/request_map_param_unmarshal.rs.jinja"),
    ),
    (
        "vec_string_refs.rs.jinja",
        include_str!("templates/vec_string_refs.rs.jinja"),
    ),
    (
        "path_unmarshal.rs.jinja",
        include_str!("templates/path_unmarshal.rs.jinja"),
    ),
    (
        "vec_string_unmarshal.rs.jinja",
        include_str!("templates/vec_string_unmarshal.rs.jinja"),
    ),
    (
        "request_string_value_unmarshal.rs.jinja",
        include_str!("templates/request_string_value_unmarshal.rs.jinja"),
    ),
    (
        "json_value_unmarshal.rs.jinja",
        include_str!("templates/json_value_unmarshal.rs.jinja"),
    ),
    (
        "wrapper_setup.rs.jinja",
        include_str!("templates/wrapper_setup.rs.jinja"),
    ),
    (
        "stream_request_unmarshal.rs.jinja",
        include_str!("templates/stream_request_unmarshal.rs.jinja"),
    ),
    (
        "stream_call_block.rs.jinja",
        include_str!("templates/stream_call_block.rs.jinja"),
    ),
    ("return_bool.rs.jinja", include_str!("templates/return_bool.rs.jinja")),
    (
        "return_byte_array.rs.jinja",
        include_str!("templates/return_byte_array.rs.jinja"),
    ),
    (
        "return_optional_byte_array.rs.jinja",
        include_str!("templates/return_optional_byte_array.rs.jinja"),
    ),
    (
        "return_primitive.rs.jinja",
        include_str!("templates/return_primitive.rs.jinja"),
    ),
    (
        "return_string.rs.jinja",
        include_str!("templates/return_string.rs.jinja"),
    ),
    (
        "return_optional_string.rs.jinja",
        include_str!("templates/return_optional_string.rs.jinja"),
    ),
    ("return_json.rs.jinja", include_str!("templates/return_json.rs.jinja")),
];

pub(crate) fn render(name: &str, context: minijinja::Value) -> String {
    let env = make_env();
    env.get_template(name)
        .unwrap_or_else(|err| panic!("missing JNI template {name}: {err}"))
        .render(context)
        .unwrap_or_else(|err| panic!("failed to render JNI template {name}: {err}"))
}

fn make_env() -> Environment<'static> {
    let mut env = Environment::new();
    env.set_trim_blocks(true);
    env.set_lstrip_blocks(true);
    env.set_keep_trailing_newline(true);
    for (name, source) in TEMPLATES {
        env.add_template(name, source)
            .unwrap_or_else(|err| panic!("failed to register JNI template {name}: {err}"));
    }
    env
}
