use crate::{controllers::admin, models::_entities::site_pages};
use loco_rs::prelude::*;
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

const ABOUT_SLUG: &str = "about";

#[derive(Debug, Deserialize)]
struct AboutParams {
    title: String,
    content: String,
}

#[derive(Debug, Serialize)]
struct PageResponse {
    id: Uuid,
    slug: String,
    title: String,
    content: String,
    updated_at: chrono::DateTime<chrono::FixedOffset>,
}

impl From<site_pages::Model> for PageResponse {
    fn from(page: site_pages::Model) -> Self {
        Self {
            id: page.id,
            slug: page.slug,
            title: page.title,
            content: page.content,
            updated_at: page.updated_at,
        }
    }
}

async fn find_about(ctx: &AppContext) -> Result<site_pages::Model> {
    site_pages::Entity::find()
        .filter(site_pages::Column::Slug.eq(ABOUT_SLUG))
        .one(&ctx.db)
        .await?
        .ok_or_else(|| Error::NotFound)
}

#[debug_handler]
async fn about(State(ctx): State<AppContext>) -> Result<Response> {
    format::json(PageResponse::from(find_about(&ctx).await?))
}

#[debug_handler]
async fn update_about(
    auth: auth::JWT,
    State(ctx): State<AppContext>,
    Json(params): Json<AboutParams>,
) -> Result<Response> {
    admin::current_admin(auth, &ctx).await?;

    let page = match find_about(&ctx).await {
        Ok(page) => {
            let mut page = page.into_active_model();
            page.title = Set(params.title);
            page.content = Set(params.content);
            page.update(&ctx.db).await?
        }
        Err(Error::NotFound) => {
            site_pages::ActiveModel {
                id: Set(Uuid::new_v4()),
                slug: Set(ABOUT_SLUG.to_string()),
                title: Set(params.title),
                content: Set(params.content),
                ..Default::default()
            }
            .insert(&ctx.db)
            .await?
        }
        Err(err) => return Err(err),
    };

    format::json(PageResponse::from(page))
}

pub fn routes() -> Routes {
    Routes::new()
        .prefix("/api")
        .add("/about", get(about))
        .add("/admin/about", put(update_about))
}
