//! HTML element methods for the builder.

use super::{Element, HtmlBuilder};

/// Macro to generate element methods.
macro_rules! element_methods {
    // Regular elements (with closing tag)
    (regular: $($name:ident),* $(,)?) => {
        $(
            #[doc = concat!("Create a `<", stringify!($name), ">` element.")]
            pub fn $name(&mut self) -> Element<'_> {
                Element::new(self, stringify!($name), false)
            }
        )*
    };
    // Void elements (self-closing, no content)
    (void: $($name:ident),* $(,)?) => {
        $(
            #[doc = concat!("Create a `<", stringify!($name), ">` void element.")]
            pub fn $name(&mut self) -> Element<'_> {
                Element::new(self, stringify!($name), true)
            }
        )*
    };
}

impl HtmlBuilder {
    // Document structure
    element_methods!(regular: html, head, body, title);

    // Sections
    element_methods!(regular: header, footer, main, nav, section, article, aside);

    // Headings
    element_methods!(regular: h1, h2, h3, h4, h5, h6);

    // Text content
    element_methods!(regular: div, p, span, pre, code, blockquote);

    // Lists
    element_methods!(regular: ul, ol, li, dl, dt, dd);

    // Tables
    element_methods!(regular: table, thead, tbody, tfoot, tr, th, td, caption, colgroup);

    // Forms
    element_methods!(regular: form, fieldset, legend, label, button, select, option, optgroup, textarea, datalist, output);

    // Inline elements
    element_methods!(regular: a, strong, em, small, mark, del, ins, sub, sup, abbr, cite, dfn, kbd, samp, var, time, data, ruby, rt, rp, bdi, bdo, q, s, u, i, b);

    // Media
    element_methods!(regular: figure, figcaption, picture, audio, video, object, iframe, canvas, svg, math);

    // Interactive
    element_methods!(regular: details, summary, dialog, menu);

    // Scripting
    element_methods!(regular: script, noscript, template, slot);

    // Other
    element_methods!(regular: style, address, progress, meter);

    // Void elements (no closing tag)
    element_methods!(void: area, base, br, col, hr, img, input, link, meta, param, source, track, wbr, embed);
}

// Additional convenience methods
impl HtmlBuilder {
    /// Create a link element with href.
    pub fn link_to(&mut self, href: &str) -> Element<'_> {
        let elem = self.a();
        elem.attr("href", href)
    }

    /// Create an image element with src and alt.
    pub fn image(&mut self, src: &str, alt: &str) -> Element<'_> {
        let elem = self.img();
        elem.attr("src", src).attr("alt", alt)
    }

    /// Create a submit button.
    pub fn submit_button(&mut self) -> Element<'_> {
        let elem = self.button();
        elem.attr("type", "submit")
    }

    /// Create a text input.
    pub fn text_input(&mut self, name: &str) -> Element<'_> {
        let elem = self.input();
        elem.attr("type", "text").attr("name", name)
    }

    /// Create an email input.
    pub fn email_input(&mut self, name: &str) -> Element<'_> {
        let elem = self.input();
        elem.attr("type", "email").attr("name", name)
    }

    /// Create a password input.
    pub fn password_input(&mut self, name: &str) -> Element<'_> {
        let elem = self.input();
        elem.attr("type", "password").attr("name", name)
    }

    /// Create a hidden input.
    pub fn hidden_input(&mut self, name: &str, value: &str) -> Element<'_> {
        let elem = self.input();
        elem.attr("type", "hidden").attr("name", name).attr("value", value)
    }

    /// Create a checkbox input.
    pub fn checkbox(&mut self, name: &str) -> Element<'_> {
        let elem = self.input();
        elem.attr("type", "checkbox").attr("name", name)
    }

    /// Create a radio input.
    pub fn radio(&mut self, name: &str, value: &str) -> Element<'_> {
        let elem = self.input();
        elem.attr("type", "radio").attr("name", name).attr("value", value)
    }

    /// Add a line break.
    pub fn line_break(&mut self) -> &mut Self {
        self.br().end()
    }

    /// Add a horizontal rule.
    pub fn horizontal_rule(&mut self) -> &mut Self {
        self.hr().end()
    }
}

#[cfg(test)]
mod tests {
    use crate::html::Html;

    #[test]
    fn test_link_to() {
        let html = Html::new().link_to("/home").text("Home").build();
        assert_eq!(html.as_str(), "<a href=\"/home\">Home</a>");
    }

    #[test]
    fn test_image() {
        let html = Html::new().image("/logo.png", "Logo").end().build();
        assert_eq!(html.as_str(), "<img src=\"/logo.png\" alt=\"Logo\">");
    }

    #[test]
    fn test_form_elements() {
        let html = Html::new()
            .form()
            .attr("action", "/submit")
            .attr("method", "post")
            .children(|h| {
                h.text_input("username")
                    .attr("placeholder", "Username")
                    .end()
                    .password_input("password")
                    .end()
                    .submit_button()
                    .text("Login")
            })
            .build();

        assert!(html.as_str().contains("<form action=\"/submit\" method=\"post\">"));
        assert!(html.as_str().contains("<input type=\"text\" name=\"username\""));
        assert!(html.as_str().contains("<input type=\"password\" name=\"password\">"));
        assert!(html.as_str().contains("<button type=\"submit\">Login</button>"));
    }
}
