//! Open Graph meta tags (`<meta property="og:*">`).

use html_escape::encode_double_quoted_attribute;

use crate::types::PageSeo;

/// Render all Open Graph tags derived from `seo.og`.
pub fn render_og_tags(seo: &PageSeo) -> String {
    let og = &seo.og;
    let mut out = String::new();

    out.push_str(&meta_property("og:type", og.og_type.as_str()));
    out.push_str(&meta_property("og:title", &og.title));
    out.push_str(&meta_property("og:url", &og.url));

    if let Some(desc) = &og.description {
        out.push_str(&meta_property("og:description", desc));
    }
    if let Some(site_name) = &og.site_name {
        out.push_str(&meta_property("og:site_name", site_name));
    }
    if let Some(locale) = &og.locale {
        out.push_str(&meta_property("og:locale", locale));
    }
    if let Some(img) = &og.image {
        out.push_str(&meta_property("og:image", &img.url));
        if let Some(alt) = &img.alt {
            out.push_str(&meta_property("og:image:alt", alt));
        }
        if let Some(w) = img.width {
            out.push_str(&meta_property("og:image:width", &w.to_string()));
        }
        if let Some(h) = img.height {
            out.push_str(&meta_property("og:image:height", &h.to_string()));
        }
        if let Some(mt) = &img.mime_type {
            out.push_str(&meta_property("og:image:type", mt));
        }
    }
    out
}

fn meta_property(property: &str, content: &str) -> String {
    format!(
        r#"<meta property="{}" content="{}">"#,
        property,
        encode_double_quoted_attribute(content)
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::types::{OgImage, OgType, PageSeo};

    #[test]
    fn renders_minimum_tags() {
        let seo = PageSeo::new("Home", "https://example.com/", "en");
        let html = render_og_tags(&seo);
        assert!(html.contains(r#"property="og:type" content="website""#));
        assert!(html.contains(r#"property="og:title" content="Home""#));
        assert!(html.contains(r#"property="og:url" content="https://example.com/""#));
    }

    #[test]
    fn renders_image_block() {
        let mut seo = PageSeo::new("Home", "https://example.com/", "en");
        seo.og.image = Some(OgImage {
            url: "https://example.com/og.png".into(),
            alt: Some("preview".into()),
            width: Some(1200),
            height: Some(630),
            mime_type: Some("image/png".into()),
        });
        let html = render_og_tags(&seo);
        assert!(html.contains(r#"property="og:image" content="https://example.com/og.png""#));
        assert!(html.contains(r#"property="og:image:alt" content="preview""#));
        assert!(html.contains(r#"property="og:image:width" content="1200""#));
        assert!(html.contains(r#"property="og:image:height" content="630""#));
        assert!(html.contains(r#"property="og:image:type" content="image/png""#));
    }

    #[test]
    fn switches_og_type_to_article() {
        let mut seo = PageSeo::new("Post", "https://example.com/blog/x", "en");
        seo.og.og_type = OgType::Article;
        let html = render_og_tags(&seo);
        assert!(html.contains(r#"property="og:type" content="article""#));
    }

    #[test]
    fn escapes_attribute_quotes() {
        let mut seo = PageSeo::new(r#"He said "hi""#, "https://example.com/", "en");
        seo.og.title = r#"He said "hi""#.into();
        let html = render_og_tags(&seo);
        assert!(html.contains(r#"content="He said &quot;hi&quot;""#));
    }
}
