use crate::database::{article::Article, PsqlData};
use axum::{
    extract::{Extension, Path},
    http::StatusCode,
    response::IntoResponse,
    routing::{get, Router},
};
use sqlx::PgPool;
use std::{collections::HashMap, error::Error};

use super::{
    templates::{ArticleTemplate, BlogFooterTemplate, BlogTemplate, HtmlTemplate},
    AppState,
};

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

async fn blog(state: Extension<AppState>) -> impl IntoResponse {
    let blog_page = BlogTemplate {
        articles: match get_articles_date_sorted(&state.db).await {
            Ok(list) => list,
            Err(_) => Vec::new(),
        }
    };
    HtmlTemplate(blog_page)
}

async fn article(
    state: Extension<AppState>,
    Path(params): Path<HashMap<String, String>>,
) -> Result<impl IntoResponse, StatusCode> {
    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(_) => return Err(StatusCode::NOT_FOUND),
    };
    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 {
        content: article.content,
        footer: footer.to_string(),
    };
    Ok(HtmlTemplate(template))
}

pub async fn get_articles_date_sorted(pool: &PgPool) -> Result<Vec<Article>, Box<dyn Error>> {
    let mut articles: Vec<Article> = match Article::read_all(pool).await {
        Ok(a) => a.iter().map(|x| *x.clone()).collect(),
        Err(_) => Vec::new(),
    };

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