use indieweb::http::Client;
use indieweb::standards::webmention::{process_incoming_webmention, Request};
use indieweb::algorithms::ptd::is_reply_context_property;
use indieweb::mf2::types::{PropertyValue, FindItemByProperty};
use serde::Serialize;
use url::Url;

#[derive(Serialize)]
pub struct PtdResult {
    pub source: String,
    pub target: String,
    pub post_type: String,
    pub reasoning: PtdReasoning,
}

#[derive(Serialize)]
pub struct PtdReasoning {
    pub matched_properties: Vec<String>,
    pub all_properties: Vec<String>,
    pub contextual_properties: Vec<String>,
    pub source_item_found: bool,
    pub document_class: Option<String>,
}

pub async fn run(
    client: &impl Client,
    source: &Url,
    target: &Url,
    token: Option<&str>,
) -> miette::Result<PtdResult> {
    let request = Request {
        source: source.clone(),
        target: target.clone(),
        private: None,
        vouch: vec![],
        token: token.map(ToString::to_string),
    };

    let relationship = process_incoming_webmention(client, &request).await?;

    let document = &relationship.document;

    let target_prop: PropertyValue = PropertyValue::Url(target.clone().into());
    let matched_property_names: Vec<String> = document
        .find_items_with_matching_property_value(target_prop)
        .into_iter()
        .map(|(name, _)| name)
        .collect();

    let all_properties: Vec<String> = if let Some(ref item) = relationship.source {
        item.properties.keys().cloned().collect()
    } else if document.items.len() == 1 {
        document.items[0].properties.keys().cloned().collect()
    } else {
        vec![]
    };

    let contextual_properties: Vec<String> = all_properties
        .iter()
        .filter(|p| is_reply_context_property(p.as_str()))
        .cloned()
        .collect();

    let document_class = document.items.first().and_then(|item| {
        item.r#type.first().map(|c| c.to_string())
    });

    Ok(PtdResult {
        source: source.to_string(),
        target: target.to_string(),
        post_type: relationship.r#type.to_string(),
        reasoning: PtdReasoning {
            matched_properties: matched_property_names,
            all_properties,
            contextual_properties,
            source_item_found: relationship.source.is_some(),
            document_class,
        },
    })
}
