use ellipse::Ellipse;

pub static POSTS_PER_PAGE: usize = 20;

/// Return a pretty location specifier from a geo: URI.
fn decode_geo_uri(uri: &str) -> String {
    if let Some(part) = uri.split(':').collect::<Vec<_>>().get(1) {
        if let Some(part) = part.split(';').next() {
            let mut parts = part.split(',');
            let lat = parts.next().unwrap();
            let lon = parts.next().unwrap();

            // TODO - format them as proper latitude and longitude
            format!("{}, {}", lat, lon)
        } else {
            uri.to_string()
        }
    } else {
        uri.to_string()
    }
}

markup::define! {
    Entry<'a>(post: &'a serde_json::Value, from_feed: bool) {
        @if post.pointer("/properties/like-of").is_none() && post.pointer("/properties/bookmark-of").is_none() {
            @FullEntry { post, from_feed: *from_feed }
        } else {
            // Show a mini-post.
            @MiniEntry { post }
        }
    }
    MiniEntry<'a>(post: &'a serde_json::Value) {
        article."h-entry mini-entry" {
            @if let Some(author) = post["properties"]["author"][0].as_object() {
                span."mini-h-card"."u-author" {
                    a."u-author"[href=author["properties"]["uid"][0].as_str().unwrap()] {
                        @if let Some(photo) = author["properties"]["photo"][0].as_str() {
                            img[src=photo, loading="lazy"];
                        } else if author["properties"]["photo"][0].is_object() {
                            img[
                                src=author["properties"]["photo"][0]["value"].as_str().unwrap(),
                                alt=author["properties"]["photo"][0]["alt"].as_str().unwrap(),
                                loading="lazy"
                            ];
                        }
                        @author["properties"]["name"][0].as_str().unwrap()
                    }
                }
                @if post["properties"].as_object().unwrap().contains_key("like-of") {
                    " "
                    span."like-icon"["aria-label"="liked"] {
                        span."like-icon-label"["aria-hidden"="true"] {
                            "❤️"
                        }
                    }
                    " "
                    @if let Some(likeof) = post["properties"]["like-of"][0].as_str() {
                        a."u-like-of"[href=likeof] { @likeof }
                    } else if let Some(likeof) = post["properties"]["like-of"][0].as_object() {
                        a."u-like-of"[href=likeof["properties"]["url"][0].as_str().unwrap()] {
                            @likeof["properties"]["name"][0]
                            .as_str()
                            .and_then(|s| if s.trim().is_empty() { None } else { Some(s) })
                            .unwrap_or_else(|| likeof["properties"]["url"][0].as_str().unwrap())
                        }
                    }
                } else if post["properties"].as_object().unwrap().contains_key("bookmark-of") {
                    " "
                    span."bookmark-icon"["aria-label"="bookmarked"] {
                        span."bookmark-icon-label"["aria-hidden"="true"] {
                            "🔖"
                        }
                    }
                    " "
                    @if let Some(bookmarkof) = post["properties"]["bookmark-of"][0].as_str() {
                        a."u-bookmark-of"[href=bookmarkof] { @bookmarkof }
                    } else if let Some(bookmarkof) = post["properties"]["bookmark-of"][0].as_object() {
                        a."u-bookmark-of"[href=bookmarkof["properties"]["url"][0].as_str().unwrap()] {
                            @bookmarkof["properties"]["name"][0]
                                .as_str()
                                .and_then(|s| if s.trim().is_empty() { None } else { Some(s) })
                                .unwrap_or_else(|| bookmarkof["properties"]["url"][0].as_str().unwrap())
                        }
                    }
                }
                " "
                a."u-url"."u-uid"[href=post["properties"]["uid"][0].as_str().unwrap()] {
                    @if let Some(published) = post["properties"]["published"][0].as_str() {
                        time."dt-published"[datetime=published] {
                            @chrono::DateTime::parse_from_rfc3339(published)
                                .map(|dt| dt.format("on %a %b %e %T %Y").to_string())
                                .unwrap_or("sometime in the past".to_string())
                        }
                    } else {
                        "sometime in the past"
                    }
                }
            }
        }
    }
    FullEntry<'a>(post: &'a serde_json::Value, from_feed: bool) {
        article."h-entry" {
            header.metadata {
                @if let Some(name) = post["properties"]["name"][0].as_str() {
                    h1."p-name" { @name }
                }
                @if let Some(author) = post["properties"]["author"][0].as_object() {
                    section."mini-h-card" {
                        a.larger."u-author"[href=author["properties"]["uid"][0].as_str().unwrap()] {
                            @if let Some(photo) = author["properties"]["photo"][0].as_str() {
                                img[src=photo, loading="lazy"];
                            } else if let Some(photo) = author["properties"]["photo"][0].as_object() {
                                img[
                                    src=photo["value"].as_str().unwrap(),
                                    alt=photo["alt"].as_str().unwrap(),
                                    loading="lazy"
                                ];
                            }

                            @author["properties"]["name"][0].as_str().unwrap()
                        }
                    }
                }
                div {
                    span {
                        a."u-url"."u-uid"[href=post["properties"]["uid"][0].as_str().unwrap(), rel=(!from_feed).then_some("canonical")] {
                            @if let Some(published) = post["properties"]["published"][0].as_str() {
                                time."dt-published"[datetime=published] {
                                    @chrono::DateTime::parse_from_rfc3339(published)
                                        .map(|dt| dt.format("%a %b %e %T %Y").to_string())
                                        .unwrap_or("sometime in the past".to_string())
                                }
                            }
                        }
                    }
                    @if post["properties"]["visibility"][0].as_str().unwrap_or("public") != "public" {
                        span."p-visibility"[value=post["properties"]["visibility"][0].as_str().unwrap()] {
                            @post["properties"]["visibility"][0].as_str().unwrap()
                        }
                    }
                    @if post["properties"]["category"].is_array() {
                        span {
                            ul.categories {
                                "Tagged: "
                                @for cat in post["properties"]["category"].as_array().unwrap() {
                                    li."p-category" { @cat.as_str().unwrap() }
                                }
                            }
                        }
                    }
                    @if post["properties"]["in-reply-to"].is_array() {
                        span {
                            "In reply to: "
                            ul.replyctx {
                                @for ctx in post["properties"]["in-reply-to"].as_array().unwrap() {
                                    @if let Some(ctx) = ctx.as_str() {
                                        li {
                                            a."u-in-reply-to"[href=ctx] {
                                                @ctx.truncate_ellipse(48).as_ref()
                                            }
                                        }
                                    } else if let Some(ctx) = ctx.as_object() {
                                        li {
                                            a."u-in-reply-to"[href=ctx["properties"]["uid"][0]
                                                              .as_str()
                                                              .unwrap_or_else(|| ctx["properties"]["url"][0].as_str().unwrap())]
                                            {
                                                @ctx["properties"]["uid"][0]
                                                    .as_str()
                                                    .unwrap_or_else(|| ctx["properties"]["url"][0].as_str().unwrap())
                                                    .truncate_ellipse(48)
                                                    .as_ref()
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                @if post["properties"]["url"].as_array().unwrap().len() > 1 {
                    hr;
                    ul {
                        "Pretty permalinks for this post:"
                        @for url in post["properties"]["url"].as_array().unwrap().iter().filter(|i| **i != post["properties"]["uid"][0]).map(|i| i.as_str().unwrap()) {
                            li {
                                a."u-url"[href=url] { @url }
                            }
                        }
                    }
                }
                @if let Some(links) = post["properties"]["syndication"].as_array() {
                    @if !links.is_empty() {
                        hr;
                        ul {
                            "Also published on:"
                            @for url in links.iter().filter_map(|i| i.as_str()) {
                                li { a."u-syndication"[href=url] { @url } }
                            }
                        }
                    }
                }
                @if post["properties"]["location"].is_array() || post["properties"]["checkin"].is_array() {
                    div {
                        @if post["properties"]["checkin"].is_array() {
                            span {
                                "Check-in to: "
                                @if post["properties"]["checkin"][0].is_string() {
                                    // It's a URL
                                    a."u-checkin"[href=post["properties"]["checkin"][0].as_str().unwrap()] {
                                        @post["properties"]["checkin"][0].as_str().unwrap().truncate_ellipse(24).as_ref()
                                    }
                                } else {
                                    a."u-checkin"[href=post["properties"]["checkin"][0]["properties"]["uid"][0].as_str().unwrap()] {
                                        @post["properties"]["checkin"][0]["properties"]["name"][0].as_str().unwrap()
                                    }
                                }
                            }
                        }
                        @if post["properties"]["location"].is_array() {
                            span {
                                "Location: "
                                @if post["properties"]["location"][0].is_string() {
                                    // It's a geo: URL
                                    // We need to decode it
                                    a."u-location"[href=post["properties"]["location"][0].as_str().unwrap()] {
                                        @decode_geo_uri(post["properties"]["location"][0].as_str().unwrap())
                                    }
                                } else {
                                    // It's an inner h-geo object
                                    a."u-location"[href=post["properties"]["location"][0]["value"].as_str().map(|x| x.to_string()).unwrap_or(format!("geo:{},{}", post["properties"]["location"][0]["properties"]["latitude"][0].as_str().unwrap(), post["properties"]["location"][0]["properties"]["longitude"][0].as_str().unwrap()))] {
                                        // I'm a lazy bitch
                                        @decode_geo_uri(&post["properties"]["location"][0]["value"].as_str().map(|x| x.to_string()).unwrap_or(format!("geo:{},{}", post["properties"]["location"][0]["properties"]["latitude"][0].as_str().unwrap(), post["properties"]["location"][0]["properties"]["longitude"][0].as_str().unwrap())))
                                    }
                                }
                            }
                        }
                    }
                }
                @if post["properties"]["ate"].is_array() || post["properties"]["drank"].is_array() {
                    div {
                        @if let Some(ate) = post["properties"]["ate"].as_array() {
                            span { ul {
                                "Ate:"
                                @for food in ate {
                                    li {
                                        @if let Some(food) = food.as_str() {
                                            // If this is a string, it's a URL.
                                            a."u-ate"[href=food] {
                                                @food.truncate_ellipse(24).as_ref()
                                            }
                                        } else {
                                            // This is a rich food object (mm, sounds tasty! I wanna eat something tasty)
                                            a."u-ate"[href=food["properties"]["uid"][0].as_str().unwrap_or("#")] {
                                                @food["properties"]["name"][0].as_str()
                                                    .unwrap_or(food["properties"]["uid"][0].as_str().unwrap_or("#").truncate_ellipse(24).as_ref())
                                            }
                                        }
                                    }
                                }
                            } }
                        }
                        @if let Some(drank) = post["properties"]["drank"].as_array() {
                            span { ul {
                                "Drank:"
                                @for food in drank {
                                    li {
                                        @if let Some(food) = food.as_str() {
                                            // If this is a string, it's a URL.
                                            a."u-drank"[href=food] {
                                                @food.truncate_ellipse(24).as_ref()
                                            }
                                        } else {
                                            // This is a rich food object (mm, sounds tasty! I wanna eat something tasty)
                                            a."u-drank"[href=food["properties"]["uid"][0].as_str().unwrap_or("#")] {
                                                @food["properties"]["name"][0].as_str()
                                                    .unwrap_or(food["properties"]["uid"][0].as_str().unwrap_or("#").truncate_ellipse(24).as_ref())
                                            }
                                        }
                                    }
                                }
                            } }
                        }
                    }
                }
            }
            @PhotoGallery { photos: post["properties"]["photo"].as_array() }
            @if *from_feed {
                @if let Some(summary) = post["properties"]["summary"][0].as_str() {
                    p."p-summary" { @summary }
                    a[href=post["properties"]["uid"][0].as_str().unwrap()] { "Read more.." }
                } else if let Some(content) = post["properties"]["content"][0]["html"].as_str() {
                    // TODO: ellipsize content by showing only the first paragraph
                    main."e-content" {
                        @markup::raw(content.trim())
                    }
                }
            } else if let Some(content) = post["properties"]["content"][0]["html"].as_str() {
                main."e-content" {
                    @markup::raw(content.trim())
                }
            }
            @WebInteractions { post, from_feed: *from_feed }
        }
    }
    VCard<'a>(card: &'a serde_json::Value) {
        article."h-card" {
            @if card["properties"]["photo"][0].is_string() {
                img."u-photo"[src=card["properties"]["photo"][0].as_str().unwrap()];
            } else if card["properties"]["photo"][0].is_object() {
                img."u-photo"[
                    src=card["properties"]["photo"][0]["value"].as_str().unwrap(),
                    alt=card["properties"]["photo"][0]["alt"].as_str().unwrap()
                ];
            }
            h1 {
                a."u-url"."u-uid"."p-name"[href=card["properties"]["uid"][0].as_str().unwrap()] {
                    @card["properties"]["name"][0].as_str().unwrap()
                }
            }
            @if card["properties"]["pronoun"].is_array() {
                span {
                    "("
                    @for (i, pronoun) in card["properties"]["pronoun"].as_array().unwrap().iter().filter_map(|v| v.as_str()).enumerate() {
                        span."p-pronoun" {
                            @pronoun
                        }
                        // Insert commas between multiple sets of pronouns
                        @if i < (card["properties"]["pronoun"].as_array().unwrap().len() - 1) {", "}
                    }
                    ")"
                }
            }
            @if card["properties"]["note"].is_array() {
                p."p-note" {
                    @card["properties"]["note"][0]["value"].as_str().unwrap_or_else(|| card["properties"]["note"][0].as_str().unwrap())
                }
            }
            @if card["properties"]["url"].is_array() {
                ul {
                    "Can be found elsewhere at:"
                    @for url in card["properties"]["url"]
                    .as_array()
                    .unwrap()
                    .iter()
                    .filter_map(|v| v.as_str())
                    .filter(|v| v != &card["properties"]["uid"][0].as_str().unwrap())
                    .filter(|v| !card["properties"]["author"][0].as_str().is_some_and(|a| v.starts_with(a)))
                    {
                        li { a."u-url"[href=url, rel="me"] { @url } }
                    }
                }
            }
        }
    }
    Food<'a>(food: &'a serde_json::Value) {
        article."h-food" {
            header.metadata {
                h1 {
                    a."p-name"."u-url"[href=food["properties"]["url"][0].as_str().unwrap()] {
                        @food["properties"]["name"][0].as_str().unwrap()
                    }
                }
            }
            @PhotoGallery { photos: food["properties"]["photo"].as_array() }
        }
    }
    Feed<'a>(feed: &'a serde_json::Value, cursor: Option<&'a str>) {
        div."h-feed" {
            div.metadata {
                @if feed["properties"]["name"][0].is_string() {
                    h1."p-name".titanic {
                        a[href=feed["properties"]["uid"][0].as_str().unwrap(), rel="feed"] {
                            @feed["properties"]["name"][0].as_str().unwrap()
                        }
                    }
                }
            }
            @if feed["children"].is_array() {
                @for child in feed["children"].as_array().unwrap() {
                    @match child["type"][0].as_str().unwrap() {
                        "h-entry" => { @Entry { post: child, from_feed: true, } }
                        "h-feed" => { @Feed { feed: child, cursor: None } }
                        "h-food" => { @Food { food: child } }
                        //"h-event" => { }
                        "h-card" => { @VCard { card: child } }
                        something_else => {
                            p {
                                "There's supposed to be an "
                                    @something_else
                                    " object here. But Kittybox can't render it right now."
                                    small { "Sorry! TToTT" }
                            }
                        }
                    }
                }
            }
            @if let Some(cursor) = cursor {
                a[rel="prev", href=format!("{}?after={}", feed["properties"]["uid"][0].as_str().unwrap(), cursor)] {
                    "Older posts"
                }
            } else {
                p {
                    "Looks like you reached the end. Wanna jump back to the "
                    a[href=feed["properties"]["uid"][0].as_str().unwrap()] {
                        "beginning"
                    } "?"
                }
            }
        }
    }

    //=======================================
    // Components library
    //=======================================
    PhotoGallery<'a>(photos: Option<&'a Vec<serde_json::Value>>) {
        @if let Some(photos) = photos {
            @for photo in photos.iter() {
                @if let Some(photo) = photo.as_str() {
                    img."u-photo"[src=photo, loading="lazy"];
                } else if photo.is_object() {
                    @if let Some(thumbnail) = photo["thumbnail"].as_str() {
                        a."u-photo"[href=photo["value"].as_str().unwrap()] {
                            img[src=thumbnail,
                                loading="lazy",
                                alt=photo["alt"].as_str().unwrap_or("")
                            ];
                        }
                    } else {
                        img."u-photo"[src=photo["value"].as_str().unwrap(),
                                      loading="lazy",
                                      alt=photo["alt"].as_str().unwrap_or("")
                        ];
                    }
                }
            }
        }
    }
    WebInteractions<'a>(post: &'a serde_json::Value, from_feed: bool) {
        footer.webinteractions {
            p[style="display: none", "aria-hidden"="false"] {
                "Webmention counters:"
            }
            ul.counters {
                li {
                    span."icon like-icon"["aria-label"="likes"] {
                        span."like-icon-label"["aria-hidden"="true"] {
                            "❤️"
                        }
                    }
                    span.counter { @post["properties"]["like"].as_array().map(|a| a.len()).unwrap_or(0) }
                }
                li {
                    span.icon["aria-label"="replies"] { "💬" }
                    span.counter { @post["properties"]["comment"].as_array().map(|a| a.len()).unwrap_or(0) }
                }
                li {
                    span.icon["aria-label"="reposts"] { "🔄" }
                    span.counter { @post["properties"]["repost"].as_array().map(|a| a.len()).unwrap_or(0) }
                }
                li {
                    span.icon["aria-label"="bookmarks"] { "🔖" }
                    span.counter { @post["properties"]["bookmark"].as_array().map(|a| a.len()).unwrap_or(0) }
                }
            }
            /*@if *from_feed && (
                post["properties"]["like"].as_array().map(|a| a.len()).unwrap_or(0)
                    + post["properties"]["bookmark"].as_array().map(|a| a.len()).unwrap_or(0)
                    + post["properties"]["repost"].as_array().map(|a| a.len()).unwrap_or(0)
                    + post["properties"]["comment"].as_array().map(|a| a.len()).unwrap_or(0)
            ) > 0 {
                details {
                    summary { "Show comments and reactions" }
                    // TODO actually render facepiles and comments
                    @if let Some(likes) = post["properties"]["like"].as_array() {
                        @if !likes.is_empty() {
                            // Show a facepile of likes for a post
                        }
                    }
                    @if let Some(bookmarks) = post["properties"]["bookmark"].as_array() {
                        @if !bookmarks.is_empty() {
                            // Show a facepile of bookmarks for a post
                        }
                    }
                    @if let Some(reposts) = post["properties"]["repost"].as_array() {
                        @if !reposts.is_empty() {
                            // Show a facepile of reposts for a post
                        }
                    }
                    @if let Some(comments) = post["properties"]["comment"].as_array() {
                        @for comment in comments.iter() {
                            // Show all the comments recursively (so we could do Salmention with them)
                        }
                    }
                }
            }*/
        }
    }
}