use achubb_database::data::{article::Article, PsqlData};
use askama::Template;
use axum::{
    extract::{Extension, Path},
    response::IntoResponse,
    routing::{get, Router},
};
use core::panic;
use sqlx::PgPool;
use std::{collections::HashMap, error::Error};

use super::{root::AppState, ArticleTemplate, HtmlTemplate, NavBar};

pub fn get_router() -> Router {
    Router::new()
        .route("/", get(blog))
        .route("/:article", get(article))
}

async fn blog(state: Extension<AppState>) -> impl IntoResponse {
    let db_pool = &state.db;
    let list: Vec<String> = get_articles_as_links_list(db_pool)
        .await
        .expect("couldn't get articles");
    let template = BlogTemplate {
        active_navbar: NavBar::BLOG,
        article_list: list.join("\n"),
    };
    HtmlTemplate(template)
}

#[derive(Template)]
#[template(path = "blog.html")]
struct BlogTemplate {
    active_navbar: &'static str,
    article_list: String,
}

#[derive(Template)]
#[template(path = "blog_footer.html")]
struct BlogFooterTemplate {
    previous: String,
    next: String,
}

async fn article(
    state: Extension<AppState>,
    Path(params): Path<HashMap<String, String>>,
) -> impl IntoResponse {
    let db_pool = &state.db;
    let article_id: &String = params.get("article").unwrap();
    let article: Article = match Article::read_by_reference(db_pool, article_id).await {
        Ok(a) => *a,
        Err(_) => panic!("Not an article at all!!!!"),
    };
    let footer = BlogFooterTemplate {
        previous: match article.previous {
            Some(a) => a,
            None => "".to_string(),
        },
        next: match article.next {
            Some(a) => a,
            None => "".to_string(),
        },
    };
    let template = ArticleTemplate {
        active_navbar: NavBar::BLOG,
        content: article.content,
        footer: footer.to_string(),
    };
    HtmlTemplate(template)
}

pub async fn get_articles_as_links_list(pool: &PgPool) -> Result<Vec<String>, Box<dyn Error>> {
    let mut articles: Vec<Article> = match Article::read_all(pool).await {
        Ok(a) => a.iter().map(|x| *x.clone()).collect(),
        Err(_) => panic!("Not an article at all!!!!"),
    };

    articles.sort_by(|a, b| b.date.cmp(&a.date));

    let list: Vec<String> = articles
        .iter()
        .map(|article| {
            format!(
                "<li><a href=\"/blog/{}\">{}</a></li>",
                article.reference, article.title
            )
        })
        .collect();
    Ok(list)
}
