//! Linux backend — GTK/Wayland.
//!
//! Architecture: correct and complete. GTK calls are stubs marked TODO.
//!
//! Each `PlatformNode` maps to a GtkWidget:
//!   element("div")    → GtkBox (vertical)
//!   element("button") → GtkButton
//!   element("input")  → GtkEntry
//!   text("...")       → GtkLabel

use crate::{EventHandler, PlatformBackend, PlatformError, PlatformNode, PlatformResult};

pub struct LinuxBackend;

impl LinuxBackend {
    pub fn new() -> Self {
        Self
    }

    fn gtk_widget(tag: &str) -> &'static str {
        match tag {
            "button" => "GtkButton",
            "input" => "GtkEntry",
            "textarea" => "GtkTextView",
            "img" => "GtkImage",
            "ul" | "ol" => "GtkListBox",
            "li" => "GtkListBoxRow",
            "nav" => "GtkHeaderBar",
            "div" | "section" | "main" | "article" | "span" => "GtkBox",
            _ => "GtkWidget",
        }
    }

    fn gtk_signal(event: &str) -> &'static str {
        match event {
            "click" => "clicked",
            "input" | "change" => "changed",
            "focus" => "focus-in-event",
            "blur" => "focus-out-event",
            "keydown" | "keypress" => "key-press-event",
            "keyup" => "key-release-event",
            _ => "event",
        }
    }
}

impl Default for LinuxBackend {
    fn default() -> Self {
        Self::new()
    }
}

impl PlatformBackend for LinuxBackend {
    fn name(&self) -> &'static str {
        "linux"
    }

    fn create_element(&self, tag: &str) -> PlatformResult<PlatformNode> {
        let mut node = PlatformNode::element(tag);
        // TODO: gtk_button_new() / gtk_box_new() / etc. via gtk-rs or raw FFI
        node.attributes
            .push(crate::Attribute::new("data-gtk-widget", Self::gtk_widget(tag)));
        Ok(node)
    }

    fn create_text(&self, content: &str) -> PlatformResult<PlatformNode> {
        let mut node = PlatformNode::text(content);
        // TODO: gtk_label_new(content)
        node.attributes
            .push(crate::Attribute::new("data-gtk-widget", "GtkLabel"));
        Ok(node)
    }

    fn set_attribute(
        &self,
        node: &mut PlatformNode,
        name: &str,
        value: &str,
    ) -> PlatformResult<()> {
        // TODO: map to GTK property setters
        //   "class" → gtk_widget_add_css_class
        //   "disabled" → gtk_widget_set_sensitive(false)
        //   "placeholder" → gtk_entry_set_placeholder_text
        node.attributes.retain(|a| a.name != name);
        node.attributes.push(crate::Attribute::new(name, value));
        Ok(())
    }

    fn remove_attribute(&self, node: &mut PlatformNode, name: &str) -> PlatformResult<()> {
        node.attributes.retain(|a| a.name != name);
        Ok(())
    }

    fn append_child(
        &self,
        parent: &mut PlatformNode,
        child: PlatformNode,
    ) -> PlatformResult<()> {
        // TODO: gtk_box_append(parent, child)
        parent.children.push(child);
        Ok(())
    }

    fn remove_child(&self, parent: &mut PlatformNode, child_index: usize) -> PlatformResult<()> {
        if child_index >= parent.children.len() {
            return Err(PlatformError::Render(format!(
                "linux: child index {} out of bounds",
                child_index
            )));
        }
        // TODO: gtk_widget_unparent(child)
        parent.children.remove(child_index);
        Ok(())
    }

    fn replace_child(
        &self,
        parent: &mut PlatformNode,
        index: usize,
        new_child: PlatformNode,
    ) -> PlatformResult<()> {
        if index >= parent.children.len() {
            return Err(PlatformError::Render("linux: replace_child out of bounds".into()));
        }
        parent.children[index] = new_child;
        Ok(())
    }

    fn bind_event(
        &self,
        node: &mut PlatformNode,
        event: &str,
        _handler: EventHandler,
    ) -> PlatformResult<()> {
        let signal = Self::gtk_signal(event);
        // TODO: g_signal_connect(widget, signal, callback, data)
        node.attributes
            .push(crate::Attribute::new(format!("data-gtk-signal-{}", event), signal));
        Ok(())
    }

    fn render_to_string(&self, node: &PlatformNode) -> PlatformResult<String> {
        Ok(node.to_html())
    }

    fn mount(&self, _root: PlatformNode, _container_id: &str) -> PlatformResult<()> {
        // TODO: get GtkWindow and call gtk_window_set_child(root)
        Ok(())
    }

    fn patch(&self, _old: &PlatformNode, _new: &PlatformNode) -> PlatformResult<()> {
        // TODO: diff and apply GTK mutations
        Ok(())
    }
}
