use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(JsonSchema, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Property {
    String(String),
    Subobject(Object),
    Multiple(Vec<Property>),
    Html { html: String, text: String },
    Image { alt: Option<String>, url: String },
    References(std::collections::BTreeMap<String, Object>),
    Url(String),
}

#[derive(JsonSchema, Serialize, Deserialize, Default)]
pub struct Object(pub std::collections::BTreeMap<String, Property>);

#[derive(JsonSchema, Serialize, Deserialize)]
pub struct HEntry {
    #[serde(rename = "type")]
    pub r#type: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub summary: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub content: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub published: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub author: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub category: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub uid: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub location: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub syndication: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "in-reply-to")]
    pub in_reply_to: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rsvp: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "like-of")]
    pub like_of: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "repost-of")]
    pub repost_of: Option<Vec<Property>>,
}

#[derive(JsonSchema, Serialize, Deserialize)]
pub struct HReview {
    #[serde(rename = "type")]
    pub r#type: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub item: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub author: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub published: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rating: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub best: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub worst: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub content: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub category: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<Vec<Property>>,
}

#[derive(JsonSchema, Serialize, Deserialize)]
pub struct HFeed {
    #[serde(rename = "type")]
    pub r#type: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub author: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub photo: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub children: Option<Vec<Property>>,
}

#[derive(JsonSchema, Serialize, Deserialize)]
pub struct HItem {
    #[serde(rename = "type")]
    pub r#type: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<Vec<Property>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub photo: Option<Vec<Property>>,
}

pub fn generate_schema<T: JsonSchema>() -> serde_json::Value {
    let schema = schemars::schema_for!(T);
    serde_json::to_value(schema).unwrap()
}