use super::*;
use crate::parse::{
    element::test::{from_html_str, grab_element_from_document},
    ElementRef,
};
use microformats_types::temporal;
use tracing_test::traced_test;
use tracing_unwrap::OptionExt;

#[traced_test]
#[test]
fn linked() -> Result<(), crate::Error> {
    let elem = grab_element_from_document(
        &from_html_str(r#"<a href='/foo' class='u-url'>a place</a>"#),
        "a",
    )
    .unwrap_or_log();

    let parser = explicit::PropertyParser::new(
        Arc::new(ElementRef {
            index: 0,
            node: Node { elem },
        }),
        DeclKind::Linked("url".to_string()),
        "http://example.com".parse()?,
    );

    assert_eq!(
        parser.expand()?,
        Some((
            "url".to_string(),
            PropertyValue::Url("http://example.com/foo".parse().unwrap())
        )),
        "expanded a direct linked property"
    );
    Ok(())
}

#[yare::parameterized(
    direct = {
        r#"<time class="dt-timing" datetime="2014-01-01"></time>"#, 
        "time", temporal::Value::Timestamp(temporal::Stamp::parse("2014-01-01")?)
    },
    abbr_title = {
        r#"<abbr class="dt-timing" title="2013-06-29">June 29</abbr>"#,
        "abbr", temporal::Value::Timestamp(temporal::Stamp::parse("2013-06-29")?)
    }
)]
fn temporal_value(html: &str, tag: &str, value: temporal::Value) -> Result<(), crate::Error> {
    let elem = grab_element_from_document(&from_html_str(html), tag).unwrap_or_log();

    let parser = explicit::PropertyParser::new(
        Arc::new(ElementRef {
            index: 0,
            node: Node { elem },
        }),
        DeclKind::Temporal("timing".to_string()),
        "http://example.com".parse()?,
    );

    assert_eq!(
        parser.expand()?,
        Some(("timing".to_string(), PropertyValue::Temporal(value))),
        "expanded a direct temporal property"
    );

    Ok(())
}

#[traced_test]
#[test]
fn html() -> Result<(), crate::Error> {
    let elem = grab_element_from_document(
        &from_html_str(r#"<span class="e-content">The name is in <strong>bold</strong>.</span>"#),
        "span",
    )
    .unwrap_or_log();

    let parser = explicit::PropertyParser::new(
        Arc::new(ElementRef {
            index: 0,
            node: Node { elem },
        }),
        DeclKind::Hypertext("content".to_string()),
        "http://example.com".parse()?,
    );

    assert_eq!(
        parser.expand()?,
        Some((
            "content".to_string(),
            PropertyValue::Fragment(Fragment {
                html: "The name is in <strong>bold</strong>.".to_string(),
                value: "The name is in bold.".to_string(),
                ..Default::default()
            })
        )),
        "expanded a direct hypertext property"
    );

    Ok(())
}

#[yare::parameterized(
    bare = { "span", r#"<span class="p-name">The name.</span>"# },
    nested = { "div", r#"<div class="p-name">
        <span class="p-nickname">The</span> <span class="p-place">name.</span>
    </div>"# },
    tag_abbr = { "abbr", r#"<abbr class="p-name value" title="The name.">Wow.</abbr>"# },
    tag_link = { "link", r#"<link class="p-name value" href='/place' title="The name." />"# },
)]
fn plain(tag_name: &str, html: &str) -> Result<(), crate::Error> {
    let elem = grab_element_from_document(&from_html_str(html), tag_name).unwrap_or_log();

    let parser = PropertyParser::new(
        Arc::new(ElementRef {
            index: 0,
            node: Node { elem },
        }),
        DeclKind::Plain("name".to_string()),
        "http://example.com".parse()?,
    );

    assert_eq!(
        parser.expand()?,
        Some((
            "name".to_string(),
            PropertyValue::Plain("The name.".to_string())
        ))
    );

    Ok(())
}

#[test]
fn plain_allow_empty() -> Result<(), crate::Error> {
    let elem = grab_element_from_document(
        &from_html_str(r#"<br class="p-honorific-suffix" />BSc<br />"#),
        "br",
    )
    .unwrap_or_log();

    let parser = PropertyParser::new(
        Arc::new(ElementRef {
            index: 0,
            node: Node { elem },
        }),
        DeclKind::Plain("honorific-suffix".to_string()),
        "http://example.com".parse()?,
    );

    assert_eq!(
        parser.expand()?,
        Some((
            "honorific-suffix".to_string(),
            PropertyValue::Plain("".to_string())
        ))
    );

    Ok(())
}
