//! iOS backend — UIKit via C FFI / Objective-C bridge.
//!
//! Architecture: correct and complete. Native UIKit calls are stubs marked
//! TODO — a future agent fills in the actual `extern "C"` calls.
//!
//! Each `PlatformNode` maps to a UIKit view:
//!   element("div")    → UIView
//!   element("span")   → UILabel (inline)
//!   element("button") → UIButton
//!   element("input")  → UITextField
//!   text("...")       → UILabel
//!
//! Event binding maps DOM event names to UIControl target-action pairs:
//!   "click" → UIControlEventTouchUpInside
//!   "input" → UIControlEventEditingChanged

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

pub struct IosBackend;

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

    /// Map an HTML tag name to the UIKit class name it maps to.
    fn uikit_class(tag: &str) -> &'static str {
        match tag {
            "button" => "UIButton",
            "input" => "UITextField",
            "textarea" => "UITextView",
            "img" => "UIImageView",
            "ul" | "ol" => "UITableView",
            "li" => "UITableViewCell",
            "nav" => "UINavigationBar",
            _ => "UIView",
        }
    }

    /// Map a DOM event name to a UIControlEvent constant name.
    fn uicontrol_event(event: &str) -> &'static str {
        match event {
            "click" => "UIControlEventTouchUpInside",
            "input" | "change" => "UIControlEventEditingChanged",
            "focus" => "UIControlEventEditingDidBegin",
            "blur" => "UIControlEventEditingDidEnd",
            _ => "UIControlEventAllEvents",
        }
    }
}

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

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

    fn create_element(&self, tag: &str) -> PlatformResult<PlatformNode> {
        let mut node = PlatformNode::element(tag);
        // TODO: call UIKit C FFI to allocate the view:
        //   extern "C" { fn el_ios_create_view(class_name: *const c_char) -> usize; }
        //   node.native_handle = Some(unsafe { el_ios_create_view(class_cstr) });
        let uikit_class = Self::uikit_class(tag);
        node.attributes
            .push(crate::Attribute::new("data-uikit-class", uikit_class));
        Ok(node)
    }

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

    fn set_attribute(
        &self,
        node: &mut PlatformNode,
        name: &str,
        value: &str,
    ) -> PlatformResult<()> {
        // TODO: map attribute names to UIKit property setters:
        //   "class" → apply style from stylesheet
        //   "disabled" → view.isUserInteractionEnabled = false
        //   "placeholder" → textField.placeholder = value
        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: [parentView addSubview:childView] via FFI
        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!(
                "ios: child index {} out of bounds",
                child_index
            )));
        }
        // TODO: [childView removeFromSuperview] via FFI
        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("ios: replace_child out of bounds".into()));
        }
        // TODO: remove old view, insert new view via FFI
        parent.children[index] = new_child;
        Ok(())
    }

    fn bind_event(
        &self,
        node: &mut PlatformNode,
        event: &str,
        _handler: EventHandler,
    ) -> PlatformResult<()> {
        let uievent = Self::uicontrol_event(event);
        // TODO: [view addTarget:target action:@selector(handler:) forControlEvents:uievent]
        node.attributes
            .push(crate::Attribute::new(format!("data-ios-event-{}", event), uievent));
        Ok(())
    }

    fn render_to_string(&self, node: &PlatformNode) -> PlatformResult<String> {
        // iOS doesn't render to HTML strings at runtime, but we support it for
        // testing and SSR fallback.
        Ok(node.to_html())
    }

    fn mount(&self, _root: PlatformNode, _container_id: &str) -> PlatformResult<()> {
        // TODO: get UIViewController by container_id and set root as its view
        Ok(())
    }

    fn patch(&self, _old: &PlatformNode, _new: &PlatformNode) -> PlatformResult<()> {
        // TODO: diff old and new trees, apply UIKit mutations via FFI
        Ok(())
    }
}
