//! Generic form field with inline validation feedback. F-11.

use html_escape::encode_double_quoted_attribute;

use crate::primitives::htmx_path;

/// Input kind. Drives the `<input>` `type` attribute.
#[derive(Debug, Clone, Copy)]
pub enum FieldKind {
    Text,
    Email,
    Password,
    Tel,
    Url,
    TextArea,
}

impl FieldKind {
    pub fn input_type(self) -> &'static str {
        match self {
            FieldKind::Text => "text",
            FieldKind::Email => "email",
            FieldKind::Password => "password",
            FieldKind::Tel => "tel",
            FieldKind::Url => "url",
            FieldKind::TextArea => "textarea",
        }
    }
}

/// Render a single form field with `hx-trigger="blur"` validation pointing at
/// `/api/htmx/validate/{form}/{name}`.
pub fn render_field(form: &str, name: &str, label: &str, kind: FieldKind) -> String {
    let endpoint = htmx_path(&format!("validate/{form}/{name}"));
    let id = format!("field-{form}-{name}");
    let body = if matches!(kind, FieldKind::TextArea) {
        format!(
            r#"<textarea id="{id}" name="{name}" hx-post="{endpoint}" hx-trigger="blur" hx-target="closest .ds-field" hx-swap="outerHTML"></textarea>"#,
            id = encode_double_quoted_attribute(&id),
            name = encode_double_quoted_attribute(name),
            endpoint = encode_double_quoted_attribute(&endpoint),
        )
    } else {
        format!(
            r#"<input type="{ty}" id="{id}" name="{name}" hx-post="{endpoint}" hx-trigger="blur" hx-target="closest .ds-field" hx-swap="outerHTML">"#,
            ty = kind.input_type(),
            id = encode_double_quoted_attribute(&id),
            name = encode_double_quoted_attribute(name),
            endpoint = encode_double_quoted_attribute(&endpoint),
        )
    };
    format!(
        r#"<div class="ds-field"><label for="{id}">{label}</label>{body}<span class="ds-field-error" data-error-for="{name}"></span></div>"#,
        id = encode_double_quoted_attribute(&id),
        label = html_escape::encode_text(label),
        name = encode_double_quoted_attribute(name),
    )
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn emits_per_field_validate_endpoint() {
        let html = render_field("contact", "email", "Email", FieldKind::Email);
        assert!(html.contains(r#"hx-post="/api/htmx/validate/contact/email""#));
    }

    #[test]
    fn triggers_on_blur() {
        let html = render_field("contact", "email", "Email", FieldKind::Email);
        assert!(html.contains(r#"hx-trigger="blur""#));
    }

    #[test]
    fn renders_textarea_for_textarea_kind() {
        let html = render_field("contact", "msg", "Message", FieldKind::TextArea);
        assert!(html.contains("<textarea"));
        assert!(!html.contains("<input"));
    }

    #[test]
    fn carries_error_target_span() {
        let html = render_field("contact", "email", "Email", FieldKind::Email);
        assert!(html.contains(r#"data-error-for="email""#));
    }
}
