use crate::ast::*;

/// Generates Rust/WASM code for the Web target.
/// 
/// # Arguments
/// * `ast` - Processed LiquidAST tree.
pub fn generate_web(ast: &LiquidAST) -> String {
    let mut output = String::new();
    
    output.push_str("use wasm_bindgen::prelude::*;
use web_sys::{window, Document, Element, HtmlElement, HtmlInputElement, InputEvent};
use std::cell::RefCell;\n\n");
    
    let custom_components: Vec<String> = ast.classes.iter()
        .filter(|c| c.extends_class == "Component")
        .map(|c| c.name.clone())
        .collect();
    
    for comp in &ast.classes {
        if comp.extends_class == "Store" {
            output.push_str(&generate_store(comp));
        } else {
            output.push_str(&generate_component(comp, &custom_components));
        }
    }
    
    output
}

/// Generates the struct definition, implementation, and helper state functions for a component class.
fn generate_component(comp: &ClassDecl, custom_components: &[String]) -> String {
    let mut code = String::new();
    
    // Declare thread-local APP_STATE for state synchronization
    code.push_str("thread_local! {\n");
    code.push_str(&format!("    static APP_STATE: RefCell<Option<{}>> = RefCell::new(None);\n", comp.name));
    code.push_str("}\n\n");
    
    // Wrapper functions for methods exported to JS/WASM
    for method in &comp.methods {
        code.push_str(&format!("#[wasm_bindgen]\npub fn web_{}() {{\n", method.name));
        code.push_str("    APP_STATE.with(|state| {\n");
        code.push_str("        if let Some(ref mut s) = *state.borrow_mut() {\n");
        code.push_str(&format!("            s.{}();\n", method.name));
        code.push_str("            let _ = s.update_dom();\n");
        code.push_str("        }\n");
        code.push_str("    });\n");
        code.push_str("}\n\n");
    }
    
    // Component Struct Definition
    code.push_str(&format!("#[wasm_bindgen]\n#[derive(Clone)]\npub struct {} {{\n", comp.name));
    for prop in &comp.properties {
        let rs_type = match prop.type_name.as_str() {
            "int" | "Int" => "i32",
            "double" | "Double" => "f64",
            "bool" | "Bool" => "bool",
            "String" => "String",
            _ => &prop.type_name,
        };
        code.push_str(&format!("    pub {}: {},\n", prop.name, rs_type));
    }
    code.push_str("}\n\n");
    
    // Implementation block
    code.push_str(&format!("#[wasm_bindgen]\nimpl {} {{\n", comp.name));
    
    // Constructor (new)
    code.push_str("    #[wasm_bindgen(constructor)]\n    pub fn new() -> Self {\n");
    code.push_str("        Self {\n");
    for prop in &comp.properties {
        let val_str = match &prop.value {
            Value::NumberLit(n) => n.clone(),
            Value::StringLit(s) => format!("\"{}\".to_string()", s),
            Value::Identifier(id) => id.clone(),
            _ => "Default::default()".to_string(),
        };
        code.push_str(&format!("            {}: {},\n", prop.name, val_str));
    }
    code.push_str("        }\n    }\n\n");
    
    // Method implementations
    for method in &comp.methods {
        let rs_type = match method.type_name.as_str() {
            "void" | "" => "()".to_string(),
            "int" | "Int" => "i32".to_string(),
            "double" | "Double" => "f64".to_string(),
            "bool" | "Bool" => "bool".to_string(),
            "String" => "String".to_string(),
            other => other.to_string(),
        };
        code.push_str(&format!("    pub fn {}(&mut self) -> {} {{\n", method.name, rs_type));
        for stmt in &method.statements {
            let translated = translate_web_statement(stmt);
            code.push_str(&format!("        {}", translated.trim_start()));
        }
        code.push_str("    }\n\n");
    }
    
    // Track DOM elements requiring dynamic state updates
    let mut update_list = Vec::new();
    let mut el_counter = 0;
    
    let root_element = &comp.render.element;
    let mut dom_generation_code = String::new();
    
    let current_var = format!("el_{}", el_counter);
    el_counter += 1;
    
    let tag = match root_element.name.as_str() {
        "Column" | "Row" | "Navigator" => "div",
        _ => "div",
    };
    
    dom_generation_code.push_str(&format!("        let {} = document.create_element(\"{}\")?;\n", current_var, tag));
    if root_element.name == "Column" || root_element.name == "Row" {
        let (align_str, spacing_str) = generate_web_layout_properties(root_element);
        let layout_dir = if root_element.name == "Column" { "column" } else { "row" };
        dom_generation_code.push_str(&format!("        {}.set_attribute(\"style\", \"display: flex; flex-direction: {}; align-items: {}; gap: {};\")?;\n", current_var, layout_dir, align_str, spacing_str));
    }
    
    if root_element.name == "Navigator" {
        let mut routes = Vec::new();
        let mut route_var = "self.current_route".to_string();
        
        for prop in &root_element.props {
            if prop.name == "initialRoute" {
                route_var = match &prop.value {
                    Value::Identifier(id) => format!("self.{}", id),
                    Value::StringLit(s) => format!("\"{}\".to_string()", s),
                    _ => "self.current_route".to_string(),
                };
            }
            if prop.name == "children" {
                if let Value::Array(arr) = &prop.value {
                    for val in arr {
                        if let Value::Element(route_el) = val {
                            if route_el.name == "Route" {
                                let mut path = String::new();
                                let mut page = String::new();
                                for rp in &route_el.props {
                                    if rp.name == "path" {
                                        if let Value::StringLit(p) = &rp.value {
                                            path = p.clone();
                                        }
                                    }
                                    if rp.name == "page" {
                                        if let Value::Identifier(pg) = &rp.value {
                                            page = pg.clone();
                                        }
                                    }
                                }
                                if !path.is_empty() && !page.is_empty() {
                                    routes.push((path, page));
                                }
                            }
                        }
                    }
                }
            }
        }
        
        let placeholder_id = format!("{}_nav", current_var);
        dom_generation_code.push_str(&format!("        {}.set_id(\"{}\");\n", current_var, placeholder_id));
        
        let mut route_render_logic = String::new();
        for (path, page) in &routes {
            route_render_logic.push_str(&format!("        if {} == \"{}\" {{\n", route_var, path));
            route_render_logic.push_str(&format!("            let mut page = {}::new();\n", page));
            route_render_logic.push_str(&format!("            page.render(\"{}\")?;\n", placeholder_id));
            route_render_logic.push_str("        }\n");
        }
        
        update_list.push((placeholder_id.clone(), format!("{{
            if let Some(container) = document.get_element_by_id(\"{}\") {{
                container.set_inner_html(\"\");
            }}
            {}
            \"\".to_string()
        }}", placeholder_id, route_render_logic)));
    } else {
        for prop in &root_element.props {
            if prop.name == "children" {
                if let Value::Array(arr) = &prop.value {
                    for val in arr {
                        if let Value::Element(child_el) = val {
                            let child_code = generate_dom_element(child_el, comp, &current_var, &mut el_counter, &mut update_list, custom_components);
                            dom_generation_code.push_str(&child_code);
                        }
                    }
                }
            }
        }
    }
    
    dom_generation_code.push_str(&format!("        parent.append_child(&{})?;\n", current_var));
    
    // update_dom function to update dynamic elements when state changes
    code.push_str("    fn update_dom(&self) -> Result<(), JsValue> {\n");
    code.push_str("        let window = window().expect(\"no global `window` exists\");\n");
    code.push_str("        let document = window.document().expect(\"should have a document on window\");\n");
    for (id, rs_expr) in &update_list {
        code.push_str(&format!("        if let Some(el) = document.get_element_by_id(\"{}\") {{\n", id));
        code.push_str(&format!("            el.set_inner_html(&{});\n", rs_expr));
        code.push_str("        }\n");
    }
    code.push_str("        Ok(())\n    }\n\n");
    
    // Main render function
    let has_on_init = comp.methods.iter().any(|m| m.name == "onInit");
    let has_on_dispose = comp.methods.iter().any(|m| m.name == "onDispose");
    
    code.push_str("    pub fn render(&mut self, parent_id: &str) -> Result<(), JsValue> {\n");
    if has_on_dispose {
        code.push_str("        APP_STATE.with(|state| {\n");
        code.push_str("            if let Some(ref mut old_s) = *state.borrow_mut() {\n");
        code.push_str("                old_s.onDispose();\n");
        code.push_str("            }\n");
        code.push_str("        });\n\n");
    }
    code.push_str("        // Register active instance to APP_STATE\n");
    code.push_str("        APP_STATE.with(|state| {\n");
    code.push_str("            *state.borrow_mut() = Some(self.clone());\n");
    code.push_str("        });\n\n");
    code.push_str("        let window = window().expect(\"no global `window` exists\");\n");
    code.push_str("        let document = window.document().expect(\"should have a document on window\");\n");
    code.push_str("        let parent = document.get_element_by_id(parent_id).expect(\"parent element not found\");\n\n");
    
    code.push_str(&dom_generation_code);
    code.push_str("        self.update_dom()?;\n");
    if has_on_init {
        code.push_str("        self.onInit();\n");
    }
    
    code.push_str("\n        Ok(())\n    }\n}\n");
    
    code
}

/// Recursively generates DOM element creation code for children.
fn generate_dom_element(
    el: &Element,
    comp: &ClassDecl,
    parent_var: &str,
    el_counter: &mut usize,
    update_list: &mut Vec<(String, String)>,
    custom_components: &[String],
) -> String {
    if el.name == "Route" {
        return String::new();
    }
    if el.name == "Empty" {
        return String::new();
    }
    
    // Check if Custom Component
    if custom_components.contains(&el.name) {
        let mut code = String::new();
        let current_var = format!("el_{}", el_counter);
        *el_counter += 1;
        
        let comp_inst_var = format!("comp_{}", el_counter);
        *el_counter += 1;
        
        code.push_str(&format!("        let {} = document.create_element(\"div\")?;\n", current_var));
        let comp_container_id = format!("{}_comp", current_var);
        code.push_str(&format!("        {}.set_id(\"{}\");\n", current_var, comp_container_id));
        code.push_str(&format!("        let mut {} = {}::new();\n", comp_inst_var, el.name));
        
        for prop in &el.props {
            let val_str = translate_web_value_expr(&prop.value);
            code.push_str(&format!("        {}.{} = {};\n", comp_inst_var, prop.name, val_str));
        }
        
        code.push_str(&format!("        {}.append_child(&{})?;\n", parent_var, current_var));
        code.push_str(&format!("        {}.render(\"{}\")?;\n\n", comp_inst_var, comp_container_id));
        
        return code;
    }
    
    // Check if Conditional If Widget
    if el.name == "If" {
        let mut code = String::new();
        let current_var = format!("el_{}", el_counter);
        *el_counter += 1;
        
        let mut condition_val = String::new();
        let mut child_el_opt = None;
        let mut fallback_el_opt = None;
        for prop in &el.props {
            match prop.name.as_str() {
                "condition" => {
                    condition_val = translate_web_value_expr(&prop.value);
                }
                "child" => {
                    if let Value::Element(child_el) = &prop.value {
                        child_el_opt = Some(child_el);
                    }
                }
                "fallback" => {
                    if let Value::Element(fallback_el) = &prop.value {
                        fallback_el_opt = Some(fallback_el);
                    }
                }
                _ => {}
            }
        }
        
        code.push_str(&format!("        let {} = document.create_element(\"div\")?;\n", current_var));
        let container_id = format!("{}_if", current_var);
        code.push_str(&format!("        {}.set_id(\"{}\");\n", current_var, container_id));
        
        let (child_html, child_args) = match child_el_opt {
            Some(child_el) => generate_web_for_format_expr(child_el, "", custom_components),
            None => ("".to_string(), Vec::new()),
        };
        let (fallback_html, fallback_args) = match fallback_el_opt {
            Some(fallback_el) => generate_web_for_format_expr(fallback_el, "", custom_components),
            None => ("".to_string(), Vec::new()),
        };
        
        let child_args_str = if child_args.is_empty() { "".to_string() } else { format!(", {}", child_args.join(", ")) };
        let fallback_args_str = if fallback_args.is_empty() { "".to_string() } else { format!(", {}", fallback_args.join(", ")) };
        
        let child_expr = format!("format!(\"{}\"{})", child_html, child_args_str);
        let fallback_expr = format!("format!(\"{}\"{})", fallback_html, fallback_args_str);
        
        let expr = format!("if {} {{ {} }} else {{ {} }}", condition_val, child_expr, fallback_expr);
        update_list.push((container_id, expr));
        
        code.push_str(&format!("        {}.append_child(&{})?;\n\n", parent_var, current_var));
        return code;
    }
    
    let mut code = String::new();
    let current_var = format!("el_{}", el_counter);
    *el_counter += 1;
    
    let tag = match el.name.as_str() {
        "Button" => "button",
        "Text" => "p",
        "TextField" => "input",
        "Column" | "Row" | "Navigator" | "Container" | "For" => "div",
        _ => "div",
    };
    
    code.push_str(&format!("        let {} = document.create_element(\"{}\")?;\n", current_var, tag));
    
    if el.name == "For" {
        let mut item_var = "item".to_string();
        let mut child_val = None;
        let mut prop_val = Value::Identifier("".to_string());
        
        for prop in &el.props {
            match prop.name.as_str() {
                "items" => {
                    prop_val = prop.value.clone();
                }
                "item" => {
                    if let Value::StringLit(s) = &prop.value {
                        item_var = s.clone();
                    }
                }
                "child" => {
                    if let Value::Element(child_el) = &prop.value {
                        child_val = Some(child_el);
                    }
                }
                _ => {}
            }
        }
        
        let container_id = format!("{}_for", current_var);
        code.push_str(&format!("        {}.set_id(\"{}\");\n", current_var, container_id));
        
        if let Some(child_el) = child_val {
            let (html_expr, args) = generate_web_for_format_expr(child_el, &item_var, custom_components);
            let items_expr = translate_web_value_expr(&prop_val);
            let args_str = if args.is_empty() {
                "".to_string()
            } else {
                format!(", {}", args.join(", "))
            };
            let expr = format!("{}.iter().map(|{}| format!(\"{}\"{})).collect::<Vec<String>>().join(\"\")", items_expr, item_var, html_expr, args_str);
            update_list.push((container_id, expr));
        }
        
        code.push_str(&format!("        {}.append_child(&{})?;\n\n", parent_var, current_var));
        return code;
    }
    
    if el.name == "TextField" {
        let mut value_var = String::new();
        let mut on_changed_cb = String::new();
        
        for prop in &el.props {
            if prop.name == "value" {
                if let Value::Identifier(id) = &prop.value {
                    value_var = id.clone();
                }
            } else if prop.name == "onChanged" {
                if let Value::Identifier(id) = &prop.value {
                    on_changed_cb = id.clone();
                }
            }
        }
        
        code.push_str(&format!("        let input_el = {}.clone().dyn_into::<HtmlInputElement>()?;\n", current_var));
        code.push_str("        input_el.set_type(\"text\");\n");
        
        let initial_val = if value_var.contains('.') {
            let parts: Vec<&str> = value_var.split('.').collect();
            let store_static = parts[0].to_uppercase();
            let prop_name = parts[1];
            format!("{}.with(|s| s.borrow().{}.clone())", store_static, prop_name)
        } else {
            format!("self.{}", value_var)
        };
        code.push_str(&format!("        input_el.set_value(&{});\n", initial_val));
        
        code.push_str("        let closure = Closure::wrap(Box::new(move |event: InputEvent| {\n");
        code.push_str("            let target = event.target().unwrap().dyn_into::<HtmlInputElement>().unwrap();\n");
        code.push_str("            APP_STATE.with(|state| {\n");
        code.push_str("                if let Some(ref mut s) = *state.borrow_mut() {\n");
        if value_var.contains('.') {
            let parts: Vec<&str> = value_var.split('.').collect();
            let store_static = parts[0].to_uppercase();
            let prop_name = parts[1];
            code.push_str(&format!("                    {}.with(|st| st.borrow_mut().{} = target.value());\n", store_static, prop_name));
        } else {
            code.push_str(&format!("                    s.{} = target.value();\n", value_var));
        }
        if !on_changed_cb.is_empty() {
            if on_changed_cb.contains('.') {
                let parts: Vec<&str> = on_changed_cb.split('.').collect();
                let store_static = parts[0].to_uppercase();
                let method_name = parts[1];
                code.push_str(&format!("                    {}.with(|st| st.borrow_mut().{}());\n", store_static, method_name));
            } else {
                code.push_str(&format!("                    s.{}();\n", on_changed_cb));
            }
        }
        code.push_str("                    let _ = s.update_dom();\n");
        code.push_str("                }\n");
        code.push_str("            });\n");
        code.push_str("        }) as Box<dyn FnMut(InputEvent)>);\n");
        code.push_str(&format!("        {}.add_event_listener_with_callback(\"input\", closure.as_ref().unchecked_ref())?;\n", current_var));
        code.push_str("        closure.forget();\n");
        
        let id_html = format!("{}_dyn", current_var);
        code.push_str(&format!("        {}.set_id(\"{}\");\n", current_var, id_html));
        
        let update_val = if value_var.contains('.') {
            let parts: Vec<&str> = value_var.split('.').collect();
            let store_static = parts[0].to_uppercase();
            let prop_name = parts[1];
            format!("{}.with(|s| s.borrow().{}.clone())", store_static, prop_name)
        } else {
            format!("self.{}", value_var)
        };
        update_list.push((id_html.clone(), format!("{{
            let window = window().unwrap();
            let document = window.document().unwrap();
            if let Some(el) = document.get_element_by_id(\"{}\") {{
                if document.active_element().as_ref() != Some(&el) {{
                    if let Ok(input) = el.dyn_into::<HtmlInputElement>() {{
                        input.set_value(&{});
                    }}
                }}
            }}
            \"\".to_string()
        }}", id_html, update_val)));
        
        code.push_str(&format!("        {}.append_child(&{})?;\n\n", parent_var, current_var));
        return code;
    }
    
    if el.name == "Container" {
        let mut css_styles = Vec::new();
        let mut child_val = None;
        for prop in &el.props {
            match prop.name.as_str() {
                "padding" => {
                    let val = translate_web_value(&prop.value).replace("\"", "");
                    css_styles.push(format!("padding: {}px", val));
                }
                "color" => {
                    let val = translate_web_value(&prop.value);
                    let clean_color = val.replace("Colors.", "").replace("Color.", "").replace("\"", "").to_lowercase();
                    css_styles.push(format!("background-color: {}", clean_color));
                }
                "borderRadius" => {
                    let val = translate_web_value(&prop.value).replace("\"", "");
                    css_styles.push(format!("border-radius: {}px", val));
                }
                "child" => {
                    child_val = Some(&prop.value);
                }
                _ => {}
            }
        }
        if !css_styles.is_empty() {
            code.push_str(&format!("        {}.set_attribute(\"style\", \"{};\")?;\n", current_var, css_styles.join("; ")));
        }
        if let Some(Value::Element(child_el)) = child_val {
            let child_code = generate_dom_element(child_el, comp, &current_var, el_counter, update_list, custom_components);
            code.push_str(&child_code);
        }
        code.push_str(&format!("        {}.append_child(&{})?;\n\n", parent_var, current_var));
        return code;
    }
    
    if el.name == "Column" || el.name == "Row" {
        let (align_str, spacing_str) = generate_web_layout_properties(el);
        let layout_dir = if el.name == "Column" { "column" } else { "row" };
        code.push_str(&format!("        {}.set_attribute(\"style\", \"display: flex; flex-direction: {}; align-items: {}; gap: {};\")?;\n", current_var, layout_dir, align_str, spacing_str));
    }
    
    if el.name == "Navigator" {
        let mut routes = Vec::new();
        let mut route_var = "self.current_route".to_string();
        
        for prop in &el.props {
            if prop.name == "initialRoute" {
                route_var = match &prop.value {
                    Value::Identifier(id) => format!("self.{}", id),
                    Value::StringLit(s) => format!("\"{}\".to_string()", s),
                    _ => "self.current_route".to_string(),
                };
            }
            if prop.name == "children" {
                if let Value::Array(arr) = &prop.value {
                    for val in arr {
                        if let Value::Element(route_el) = val {
                            if route_el.name == "Route" {
                                let mut path = String::new();
                                let mut page = String::new();
                                for rp in &route_el.props {
                                    if rp.name == "path" {
                                        if let Value::StringLit(p) = &rp.value {
                                            path = p.clone();
                                        }
                                    }
                                    if rp.name == "page" {
                                        if let Value::Identifier(pg) = &rp.value {
                                            page = pg.clone();
                                        }
                                    }
                                }
                                if !path.is_empty() && !page.is_empty() {
                                    routes.push((path, page));
                                }
                            }
                        }
                    }
                }
            }
        }
        
        let placeholder_id = format!("{}_nav", current_var);
        code.push_str(&format!("        {}.set_id(\"{}\");\n", current_var, placeholder_id));
        
        let mut route_render_logic = String::new();
        for (path, page) in &routes {
            route_render_logic.push_str(&format!("        if {} == \"{}\" {{\n", route_var, path));
            route_render_logic.push_str(&format!("            let mut page = {}::new();\n", page));
            route_render_logic.push_str(&format!("            page.render(\"{}\")?;\n", placeholder_id));
            route_render_logic.push_str("        }\n");
        }
        
        update_list.push((placeholder_id.clone(), format!("{{
            if let Some(container) = document.get_element_by_id(\"{}\") {{
                container.set_inner_html(\"\");
            }}
            {}
            \"\".to_string()
        }}", placeholder_id, route_render_logic)));
    } else {
        for prop in &el.props {
            match prop.name.as_str() {
                "label" | "text" => {
                    let val_str = match &prop.value {
                        Value::StringLit(s) => {
                            if s.contains('$') {
                                let id_html = format!("{}_dyn", current_var);
                                code.push_str(&format!("        {}.set_id(\"{}\");\n", current_var, id_html));
                                let rs_expr = translate_string_interpolation(s, "self.");
                                update_list.push((id_html, rs_expr.clone()));
                                rs_expr
                            } else {
                                format!("\"{}\".to_string()", s)
                            }
                        }
                        Value::Identifier(id) => {
                            let id_html = format!("{}_dyn", current_var);
                            code.push_str(&format!("        {}.set_id(\"{}\");\n", current_var, id_html));
                            let expr = if is_store_reference(id) {
                                let parts: Vec<&str> = id.split('.').collect();
                                let store_static = parts[0].to_uppercase();
                                let prop_name = parts[1];
                                format!("{}.with(|s| s.borrow().{}.clone())", store_static, prop_name)
                            } else {
                                format!("self.{}", id)
                            };
                            update_list.push((id_html, expr.clone()));
                            expr
                        }
                        _ => "\"\"".to_string(),
                    };
                    code.push_str(&format!("        {}.set_inner_html(&{});\n", current_var, val_str));
                }
                "onPressed" => {
                    if let Value::Identifier(method_name) = &prop.value {
                        code.push_str("        let closure = Closure::wrap(Box::new(move || {\n");
                        if is_store_reference(method_name) {
                            let parts: Vec<&str> = method_name.split('.').collect();
                            let store_inst = parts[0];
                            let method = parts[1];
                            code.push_str(&format!("            store_{}_{}();\n", store_inst, method));
                        } else {
                            code.push_str(&format!("            web_{}();\n", method_name));
                        }
                        code.push_str("        }) as Box<dyn FnMut()>);\n");
                        code.push_str(&format!("        {}.add_event_listener_with_callback(\"click\", closure.as_ref().unchecked_ref())?;\n", current_var));
                        code.push_str("        closure.forget();\n");
                    }
                }
                "style" => {
                    if let Value::Element(style_el) = &prop.value {
                        if style_el.name == "TextStyle" {
                            let mut css_styles = Vec::new();
                            for style_prop in &style_el.props {
                                match style_prop.name.as_str() {
                                    "fontSize" => {
                                        let size = translate_web_value(&style_prop.value);
                                        let clean_size = size.replace("\"", "").replace(".0", "");
                                        let px_size = if clean_size.chars().all(|c| c.is_numeric()) {
                                            format!("{}px", clean_size)
                                        } else {
                                            clean_size
                                        };
                                        css_styles.push(format!("font-size: {}", px_size));
                                    }
                                    "weight" => {
                                        let weight = translate_web_value(&style_prop.value);
                                        let clean_weight = weight.replace("FontWeight.", "").to_lowercase();
                                        let fw = match clean_weight.as_str() {
                                            "bold" => "bold",
                                            "normal" => "normal",
                                            _ => &clean_weight,
                                        };
                                        css_styles.push(format!("font-weight: {}", fw));
                                    }
                                    "color" => {
                                        let color = translate_web_value(&style_prop.value);
                                        let clean_color = color.replace("Colors.", "").replace("Color.", "").to_lowercase();
                                        css_styles.push(format!("color: {}", clean_color));
                                    }
                                    _ => {}
                                }
                            }
                            if !css_styles.is_empty() {
                                code.push_str("        // Style attribute mapping\n");
                                let existing_style = format!("{}.get_attribute(\"style\").unwrap_or_default()", current_var);
                                code.push_str(&format!("        let existing_style = {};\n", existing_style));
                                code.push_str(&format!("        {}.set_attribute(\"style\", &format!(\"{{}}; {};\", existing_style))?;\n", current_var, css_styles.join("; ")));
                            }
                        }
                    }
                }
                "children" => {
                    if let Value::Array(arr) = &prop.value {
                        for val in arr {
                            if let Value::Element(child_el) = val {
                                let child_code = generate_dom_element(child_el, comp, &current_var, el_counter, update_list, custom_components);
                                code.push_str(&child_code);
                            }
                        }
                    }
                }
                _ => {}
            }
        }
    }
    
    code.push_str(&format!("        {}.append_child(&{})?;\n\n", parent_var, current_var));
    code
}

/// Translates string literals containing variable interpolation ($var) into a Rust format! expression.
fn translate_string_interpolation(lit: &str, self_prefix: &str) -> String {
    if lit.contains('$') {
        let mut fmt_string = String::new();
        let mut vars = Vec::new();
        let chars: Vec<char> = lit.chars().collect();
        let mut i = 0;
        
        while i < chars.len() {
            if chars[i] == '$' && i + 1 < chars.len() && chars[i+1].is_alphabetic() {
                let mut var_name = String::new();
                i += 1;
                while i < chars.len() && (chars[i].is_alphanumeric() || chars[i] == '_' || chars[i] == '.') {
                    var_name.push(chars[i]);
                    i += 1;
                }
                fmt_string.push_str("{}");
                if is_store_reference(&var_name) {
                    let parts: Vec<&str> = var_name.split('.').collect();
                    let store_static = parts[0].to_uppercase();
                    let prop = parts[1];
                    vars.push(format!("{}.with(|s| s.borrow().{}.clone())", store_static, prop));
                } else {
                    vars.push(format!("{}{}", self_prefix, var_name));
                }
            } else {
                fmt_string.push(chars[i]);
                i += 1;
            }
        }
        
        if vars.is_empty() {
            format!("\"{}\".to_string()", lit)
        } else {
            format!("format!(\"{}\", {})", fmt_string, vars.join(", "))
        }
    } else {
        format!("\"{}\".to_string()", lit)
    }
}

/// Translates standard values for Web Rust/WASM generator.
fn translate_web_value(val: &Value) -> String {
    match val {
        Value::StringLit(s) => format!("\"{}\"", s),
        Value::NumberLit(n) => n.clone(),
        Value::Identifier(id) => {
            if is_store_reference(id) {
                let parts: Vec<&str> = id.split('.').collect();
                let store_static = parts[0].to_uppercase();
                let prop = parts[1];
                format!("{}.with(|s| s.borrow().{}.clone())", store_static, prop)
            } else {
                id.clone()
            }
        }
        _ => "\"\"".to_string(),
    }
}

/// Generates a Rust structure and thread-local static singleton for a Store class.
fn generate_store(comp: &ClassDecl) -> String {
    let mut code = String::new();
    
    let store_name_upper = comp.name.to_uppercase();
    
    // Declare thread-local static singleton
    code.push_str("thread_local! {\n");
    code.push_str(&format!("    pub static {}: RefCell<{}> = RefCell::new({}::new());\n", store_name_upper, comp.name, comp.name));
    code.push_str("}\n\n");
    
    // Store struct definition
    code.push_str(&format!("#[wasm_bindgen]\n#[derive(Clone)]\npub struct {} {{\n", comp.name));
    for prop in &comp.properties {
        let rs_type = match prop.type_name.as_str() {
            "int" | "Int" => "i32",
            "double" | "Double" => "f64",
            "bool" | "Bool" => "bool",
            "String" => "String",
            _ => &prop.type_name,
        };
        code.push_str(&format!("    pub {}: {},\n", prop.name, rs_type));
    }
    code.push_str("}\n\n");
    
    // Implementation block
    code.push_str(&format!("#[wasm_bindgen]\nimpl {} {{\n", comp.name));
    
    // Constructor (new)
    code.push_str("    #[wasm_bindgen(constructor)]\n    pub fn new() -> Self {\n");
    code.push_str("        Self {\n");
    for prop in &comp.properties {
        let val_str = match &prop.value {
            Value::NumberLit(n) => n.clone(),
            Value::StringLit(s) => format!("\"{}\".to_string()", s),
            Value::Identifier(id) => id.clone(),
            _ => "Default::default()".to_string(),
        };
        code.push_str(&format!("            {}: {},\n", prop.name, val_str));
    }
    code.push_str("        }\n    }\n\n");
    
    // Store Methods
    for method in &comp.methods {
        let rs_type = match method.type_name.as_str() {
            "void" | "" => "()".to_string(),
            "int" | "Int" => "i32".to_string(),
            "double" | "Double" => "f64".to_string(),
            "bool" | "Bool" => "bool".to_string(),
            "String" => "String".to_string(),
            other => other.to_string(),
        };
        code.push_str(&format!("    pub fn {}(&mut self) -> {} {{\n", method.name, rs_type));
        for stmt in &method.statements {
            let translated = translate_web_statement(stmt);
            code.push_str(&format!("        {}", translated.trim_start()));
        }
        code.push_str("    }\n\n");
    }
    code.push_str("}\n\n");
    
    // Exported helper wrapper functions
    let instance_name = format!("{}{}", &comp.name[0..1].to_lowercase(), &comp.name[1..]);
    for method in &comp.methods {
        code.push_str(&format!("#[wasm_bindgen]\npub fn store_{}_{}() {{\n", instance_name, method.name));
        code.push_str(&format!("    {}.with(|state| {{\n", store_name_upper));
        code.push_str(&format!("        state.borrow_mut().{}();\n", method.name));
        code.push_str("    });\n");
        code.push_str("}\n\n");
    }
    
    code
}

/// Translates layout spacing and alignment for Web Rust/WASM generator.
fn generate_web_layout_properties(el: &Element) -> (String, String) {
    let mut align_str = "center".to_string();
    let mut spacing_str = "16px".to_string();
    
    for prop in &el.props {
        match prop.name.as_str() {
            "alignment" => {
                let val = translate_web_value(&prop.value);
                let clean_val = val.replace("Alignment.", "").replace("\"", "").to_lowercase();
                align_str = match clean_val.as_str() {
                    "start" | "left" => "flex-start".to_string(),
                    "end" | "right" => "flex-end".to_string(),
                    "center" => "center".to_string(),
                    _ => clean_val,
                };
            }
            "spacing" => {
                let val = translate_web_value(&prop.value);
                let val_clean = val.replace("\"", "").replace(".0", "");
                spacing_str = if val_clean.chars().all(|c| c.is_numeric()) {
                    format!("{}px", val_clean)
                } else {
                    val_clean
                };
            }
            _ => {}
        }
    }
    (align_str, spacing_str)
}

fn is_store_reference(id: &str) -> bool {
    id.contains('.') && id.chars().next().map_or(false, |c| c.is_lowercase())
}

fn translate_web_value_expr(val: &Value) -> String {
    match val {
        Value::StringLit(s) => {
            if s.contains('$') {
                let mut fmt_str = String::new();
                let mut vars = Vec::new();
                let chars: Vec<char> = s.chars().collect();
                let mut i = 0;
                while i < chars.len() {
                    if chars[i] == '$' && i + 1 < chars.len() && chars[i+1].is_alphabetic() {
                        let mut var_name = String::new();
                        i += 1;
                        while i < chars.len() && (chars[i].is_alphanumeric() || chars[i] == '_' || chars[i] == '.') {
                            var_name.push(chars[i]);
                            i += 1;
                        }
                        fmt_str.push_str("{}");
                        if is_store_reference(&var_name) {
                            let parts: Vec<&str> = var_name.split('.').collect();
                            let store_static = parts[0].to_uppercase();
                            let prop_name = parts[1];
                            vars.push(format!("{}.with(|s| s.borrow().{}.clone())", store_static, prop_name));
                        } else {
                            vars.push(format!("self.{}.clone()", var_name));
                        }
                    } else {
                        fmt_str.push(chars[i]);
                        i += 1;
                    }
                }
                if vars.is_empty() {
                    format!("\"{}\".to_string()", s)
                } else {
                    format!("format!(\"{}\", {})", fmt_str, vars.join(", "))
                }
            } else {
                format!("\"{}\".to_string()", s)
            }
        }
        Value::NumberLit(n) => n.clone(),
        Value::Identifier(id) => {
            if is_store_reference(id) {
                let parts: Vec<&str> = id.split('.').collect();
                let store_static = parts[0].to_uppercase();
                let prop_name = parts[1];
                format!("{}.with(|s| s.borrow().{}.clone())", store_static, prop_name)
            } else {
                format!("self.{}.clone()", id)
            }
        }
        _ => "\"\"".to_string(),
    }
}

fn translate_web_statement(stmt: &Statement) -> String {
    match stmt {
        Statement::Return(val) => {
            let val_str = translate_web_value_expr(val);
            format!("return {};\n", val_str)
        }
        Statement::Expr(expr) => {
            if expr.name == "Http.get" {
                if let Some(ref args) = expr.args {
                    if args.len() >= 2 {
                        let url = translate_web_value_expr(&args[0]);
                        if let Value::Identifier(ref cb) = args[1] {
                            return format!("// Http.get mock\n        let _url = {};\n        self.{}(\"Mock HTTP GET Response data\".to_string());\n", url, cb);
                        }
                    }
                }
            } else if expr.name == "Http.post" {
                if let Some(ref args) = expr.args {
                    if args.len() >= 3 {
                        let url = translate_web_value_expr(&args[0]);
                        let body = translate_web_value_expr(&args[1]);
                        if let Value::Identifier(ref cb) = args[2] {
                            return format!("// Http.post mock\n        let _url = {};\n        let _body = {};\n        self.{}(\"Mock HTTP POST Response data\".to_string());\n", url, body, cb);
                        }
                    }
                }
            } else if expr.name == "Location.current" {
                if let Some(ref args) = expr.args {
                    if args.len() >= 1 {
                        if let Value::Identifier(ref cb) = args[0] {
                            return format!("// Location.current mock\n        self.{}(\"-6.2088,106.8456\".to_string());\n", cb);
                        }
                    }
                }
            } else if expr.name == "Notification.show" {
                if let Some(ref args) = expr.args {
                    if args.len() >= 2 {
                        let title = translate_web_value_expr(&args[0]);
                        let body = translate_web_value_expr(&args[1]);
                        return format!("// Notification.show mock\n        println!(\"{{}}: {{}}\", {}, {});\n", title, body);
                    }
                }
            } else if expr.name == "Storage.set" {
                if let Some(ref args) = expr.args {
                    if args.len() >= 2 {
                        let key = translate_web_value_expr(&args[0]);
                        let val = translate_web_value_expr(&args[1]);
                        return format!(
                            "window().unwrap().local_storage().unwrap().unwrap().set_item(&{}, &{}).unwrap();\n",
                            key, val
                        );
                    }
                }
            } else if expr.name == "Storage.get" {
                if let Some(ref args) = expr.args {
                    if args.len() >= 1 {
                        let key = translate_web_value_expr(&args[0]);
                        return format!(
                            "window().unwrap().local_storage().unwrap().unwrap().get_item(&{}).unwrap();\n",
                            key
                        );
                    }
                }
            }

            let mut code = String::new();
            if let Some(op) = &expr.op {
                if expr.name.contains('.') {
                    let parts: Vec<&str> = expr.name.split('.').collect();
                    let store_static = parts[0].to_uppercase();
                    let prop_name = parts[1];
                    if op == "++" {
                        code.push_str(&format!("{}.with(|s| s.borrow_mut().{} += 1);\n", store_static, prop_name));
                    } else {
                        code.push_str(&format!("{}.with(|s| s.borrow_mut().{} -= 1);\n", store_static, prop_name));
                    }
                } else {
                    if op == "++" {
                        code.push_str(&format!("self.{} += 1;\n", expr.name));
                    } else {
                        code.push_str(&format!("self.{} -= 1;\n", expr.name));
                    }
                }
            } else if expr.name.contains('.') {
                let parts: Vec<&str> = expr.name.split('.').collect();
                let store_static = parts[0].to_uppercase();
                let method_name = parts[1];
                if let Some(ref args) = expr.args {
                    let args_strs: Vec<String> = args.iter().map(|v| translate_web_value_expr(v)).collect();
                    code.push_str(&format!("{}.with(|s| s.borrow_mut().{}({}));\n", store_static, method_name, args_strs.join(", ")));
                } else {
                    code.push_str(&format!("{}.with(|s| s.borrow_mut().{}());\n", store_static, method_name));
                }
            } else {
                if let Some(ref args) = expr.args {
                    let args_strs: Vec<String> = args.iter().map(|v| translate_web_value_expr(v)).collect();
                    code.push_str(&format!("self.{}({});\n", expr.name, args_strs.join(", ")));
                } else {
                    code.push_str(&format!("self.{}();\n", expr.name));
                }
            }
            code
        }
    }
}

fn translate_rust_format_value(val: &Value, item_var: &str) -> (String, Vec<String>) {
    match val {
        Value::StringLit(s) => {
            let mut fmt_str = String::new();
            let mut args = Vec::new();
            let chars: Vec<char> = s.chars().collect();
            let mut i = 0;
            while i < chars.len() {
                if chars[i] == '$' && i + 1 < chars.len() && chars[i+1].is_alphabetic() {
                    let mut var_name = String::new();
                    i += 1;
                    while i < chars.len() && (chars[i].is_alphanumeric() || chars[i] == '_' || chars[i] == '.') {
                        var_name.push(chars[i]);
                        i += 1;
                    }
                    fmt_str.push_str("{}");
                    if var_name == item_var {
                        args.push(var_name);
                    } else if is_store_reference(&var_name) {
                        let parts: Vec<&str> = var_name.split('.').collect();
                        let store_static = parts[0].to_uppercase();
                        let prop_name = parts[1];
                        args.push(format!("{}.with(|s| s.borrow().{}.clone())", store_static, prop_name));
                    } else {
                        args.push(format!("self.{}.clone()", var_name));
                    }
                } else {
                    fmt_str.push(chars[i]);
                    i += 1;
                }
            }
            (fmt_str, args)
        }
        Value::NumberLit(n) => (n.clone(), Vec::new()),
        Value::Identifier(id) => {
            if id == item_var {
                ("{}".to_string(), vec![id.clone()])
            } else if is_store_reference(id) {
                let parts: Vec<&str> = id.split('.').collect();
                let store_static = parts[0].to_uppercase();
                let prop_name = parts[1];
                ("{}".to_string(), vec![format!("{}.with(|s| s.borrow().{}.clone())", store_static, prop_name)])
            } else {
                ("{}".to_string(), vec![format!("self.{}.clone()", id)])
            }
        }
        _ => ("".to_string(), Vec::new()),
    }
}

fn generate_web_for_format_expr(el: &Element, item_var: &str, custom_components: &[String]) -> (String, Vec<String>) {
    match el.name.as_str() {
        "Text" => {
            let mut text_val = String::new();
            let mut font_size = "".to_string();
            let mut font_weight = "".to_string();
            let mut color = "".to_string();
            let mut args = Vec::new();
            
            for prop in &el.props {
                if prop.name == "text" || prop.name == "label" {
                    let (t_fmt, mut t_args) = translate_rust_format_value(&prop.value, item_var);
                    text_val = t_fmt;
                    args.append(&mut t_args);
                } else if prop.name == "style" {
                    if let Value::Element(style_el) = &prop.value {
                        if style_el.name == "TextStyle" {
                            for sp in &style_el.props {
                                if sp.name == "fontSize" {
                                    let val = translate_web_value(&sp.value).replace("\"", "");
                                    font_size = format!("font-size: {}px;", val);
                                } else if sp.name == "weight" {
                                    let val = translate_web_value(&sp.value).replace("FontWeight.", "").to_lowercase();
                                    font_weight = format!("font-weight: {};", val);
                                } else if sp.name == "color" {
                                    let val = translate_web_value(&sp.value).replace("Colors.", "").replace("Color.", "").to_lowercase();
                                    color = format!("color: {};", val);
                                }
                            }
                        }
                    }
                }
            }
            (format!("<p style=\\\"{}{}{}\\\">{}</p>", font_size, font_weight, color, text_val), args)
        }
        "Button" => {
            let mut label = "".to_string();
            let mut click = "".to_string();
            let mut args = Vec::new();
            for prop in &el.props {
                if prop.name == "label" {
                    let (l_fmt, mut l_args) = translate_rust_format_value(&prop.value, item_var);
                    label = l_fmt;
                    args.append(&mut l_args);
                } else if prop.name == "onPressed" {
                    if let Value::Identifier(id) = &prop.value {
                        click = format!("onclick=\\\"web_{}()\\\"", id);
                    }
                }
            }
            (format!("<button {}>{}</button>", click, label), args)
        }
        "Container" => {
            let mut padding = "".to_string();
            let mut bg_color = "".to_string();
            let mut border_radius = "".to_string();
            let mut child_str = "".to_string();
            let mut args = Vec::new();
            for prop in &el.props {
                if prop.name == "padding" {
                    let val = translate_web_value(&prop.value).replace("\"", "");
                    padding = format!("padding: {}px;", val);
                } else if prop.name == "color" {
                    let val = translate_web_value(&prop.value).replace("Colors.", "").replace("Color.", "").to_lowercase();
                    bg_color = format!("background-color: {};", val);
                } else if prop.name == "borderRadius" {
                    let val = translate_web_value(&prop.value).replace("\"", "");
                    border_radius = format!("border-radius: {}px;", val);
                } else if prop.name == "child" {
                    if let Value::Element(child_el) = &prop.value {
                        let (c_fmt, mut c_args) = generate_web_for_format_expr(child_el, item_var, custom_components);
                        child_str = c_fmt;
                        args.append(&mut c_args);
                    }
                }
            }
            (format!("<div style=\\\"{}{}{}\\\">{}</div>", padding, bg_color, border_radius, child_str), args)
        }
        "Column" | "Row" => {
            let mut children_str = String::new();
            let mut args = Vec::new();
            let layout_dir = if el.name == "Column" { "column" } else { "row" };
            for prop in &el.props {
                if prop.name == "children" {
                    if let Value::Array(arr) = &prop.value {
                        for v in arr {
                            if let Value::Element(c_el) = v {
                                let (c_fmt, mut c_args) = generate_web_for_format_expr(c_el, item_var, custom_components);
                                children_str.push_str(&c_fmt);
                                args.append(&mut c_args);
                            }
                        }
                    }
                }
            }
            (format!("<div style=\\\"display: flex; flex-direction: {};\\\">{}</div>", layout_dir, children_str), args)
        }
        "If" => {
            let mut condition_val = String::new();
            let mut child_el_opt = None;
            let mut fallback_el_opt = None;
            
            for prop in &el.props {
                if prop.name == "condition" {
                    condition_val = translate_web_value_expr(&prop.value);
                } else if prop.name == "child" {
                    if let Value::Element(child_el) = &prop.value {
                        child_el_opt = Some(child_el);
                    }
                } else if prop.name == "fallback" {
                    if let Value::Element(fallback_el) = &prop.value {
                        fallback_el_opt = Some(fallback_el);
                    }
                }
            }
            
            let (child_html, child_args) = match child_el_opt {
                Some(child_el) => generate_web_for_format_expr(child_el, item_var, custom_components),
                None => ("".to_string(), Vec::new()),
            };
            let (fallback_html, fallback_args) = match fallback_el_opt {
                Some(fallback_el) => generate_web_for_format_expr(fallback_el, item_var, custom_components),
                None => ("".to_string(), Vec::new()),
            };
            
            let mut combined_args = Vec::new();
            let mut child_args_expr = String::new();
            let mut fallback_args_expr = String::new();
            
            if !child_args.is_empty() {
                child_args_expr = format!(", {}", child_args.join(", "));
            }
            if !fallback_args.is_empty() {
                fallback_args_expr = format!(", {}", fallback_args.join(", "));
            }
            
            let child_expr = format!("format!(\"{}\"{})", child_html, child_args_expr);
            let fallback_expr = format!("format!(\"{}\"{})", fallback_html, fallback_args_expr);
            
            let cond_expr = format!("if {} {{ {} }} else {{ {} }}", condition_val, child_expr, fallback_expr);
            combined_args.push(cond_expr);
            
            ("{}".to_string(), combined_args)
        }
        name if custom_components.contains(&name.to_string()) => {
            (format!("<div class=\\\"{}\\\"></div>", name), Vec::new())
        }
        _ => ("".to_string(), Vec::new())
    }
}
