use super::response::success_askama;
use super::route_prelude::*;
use crate::nostru::notes_filter;
use crate::rendering::{lnk, render_notes};
use http::Uri;
use mdiu::{Gemtext, Markup};
use std::collections::HashSet;

#[derive(Template, Clone)]
#[template(path = "hashtag_notes.gmi", escape = "txt")]
struct HashTagContentTemplate {
    req_url: Url,
    hashtag: String,
    note_blocks: Vec<Block>,
}

/// Lists all known hashtags
pub async fn hashtags_index(
    _ctx: RouteContext,
    user: &'static mut CaracalUser,
) -> Result<Response, UserError> {
    let filter = Filter::new().kind(Kind::TextNote);

    let events = user.client.database().query(filter).await?;

    let mut tags: HashSet<String> = HashSet::new();
    for event in events.iter() {
        tags.extend(event.tags.hashtags().map(str::to_string));
    }

    let mut sorted_hashtags = tags.into_iter().collect::<Vec<_>>();
    sorted_hashtags.sort();

    let mut document = vec![];

    for hashtag in sorted_hashtags {
        if hashtag.is_empty() {
            continue;
        }

        match Uri::builder()
            .path_and_query(format!("/hashtags/{}/notes", encode(&hashtag)))
            .build()
        {
            Ok(tag_uri) => document.push(lnk(tag_uri, Some(hashtag))),
            Err(error) => {
                eprintln!("Cannot build URI for tag {}: {}", hashtag, error)
            }
        }
    }

    Ok(Response::success(<Gemtext>::markup(&document)))
}

/// Lists all the notes tagged with a hashtag
pub async fn notes_by_hashtag(
    ctx: RouteContext,
    user: &'static mut CaracalUser,
) -> Result<Response, UserError> {
    let hashtag = decode(ctx.parameters.get("hashtag").unwrap())?;

    let filter = notes_filter().limit(500).hashtag(&*hashtag);

    user.client.subscribe(filter.clone(), None).await?;

    let events = user.db_query(filter).await?;

    let note_blocks = render_notes(
        user.events_filter_muted(&events).await,
        &user.client,
        None,
        None,
        NoteRenderOptions::default(),
    )
    .await?;

    Ok(success_askama!(HashTagContentTemplate {
        req_url: ctx.url,
        hashtag: hashtag.to_string(),
        note_blocks,
    }))
}
