use super::blog::get_articles_as_links_list;
use crate::{
    database::{link::{Link, LinkType}, PsqlData},
    html::AppState,
};
use axum::{response::IntoResponse, routing::get, Extension, Router};
use sqlx::PgPool;
use std::error::Error;
use rand::{seq::SliceRandom, thread_rng};

pub fn get_router() -> Router {
    Router::new()
        .route("/articles", get(blogs))
        .route("/recentarticles", get(recent_blogs))
        .route("/blogrolllinks", get(blogroll_links))
        .route("/articlelinks", get(article_links))
}

async fn blogs(state: Extension<AppState>) -> impl IntoResponse {
    let db_pool = &state.db;
    let article_list: Vec<String> = get_articles_as_links_list(db_pool)
        .await
        .expect("couldn't get articles");

    article_list.join("\n")
}

async fn recent_blogs(state: Extension<AppState>) -> impl IntoResponse {
    let db_pool = &state.db;
    let article_list: Vec<String> = get_articles_as_links_list(db_pool)
        .await
        .expect("couldn't get articles");

    let (article_head, _) = article_list.split_at(5);

    article_head.join("\n")
}

async fn blogroll_links(state: Extension<AppState>) -> impl IntoResponse {
    let db_pool = &state.db;
    let blogroll_list: Vec<String> = get_links_as_list(db_pool, LinkType::BLOG)
        .await
        .expect("couldn't get blogroll links");

    blogroll_list.join("\n<hr>\n")
}

async fn article_links(state: Extension<AppState>) -> impl IntoResponse {
    let db_pool = &state.db;
    let blogroll_list: Vec<String> = get_links_as_list(db_pool, LinkType::ARTICLE)
        .await
        .expect("couldn't get blogroll links");

    blogroll_list.join("\n<hr>\n")
}

pub async fn get_links_as_list(pool: &PgPool, link_type: LinkType) -> Result<Vec<String>, Box<dyn Error>> {
    let mut links: Vec<Link> = match Link::read_all(pool).await {
        Ok(a) => a.iter().map(|x| *x.clone()).collect(),
        Err(_) => Vec::new(),
    };
    
    let mut rng = thread_rng();
    links.shuffle(&mut rng);

    let list: Vec<String> = links
        .iter()
        .filter(|link| link.link_type == link_type)
        .map(|link| {
            let title: String = match &link.title {
                Some(t) => t.to_string(),
                None => link.url.clone(),
            };
            format!(
                "<li><a href=\"{}\">{}</a>:<br>{}</li>",
                link.url, 
                title, 
                match &link.description {
                    Some(d) => d,
                    None => "",
                }
            )
        })
        .collect();
    Ok(list)
}
