use crate::website::{Page, PageTemplate, WebSite};
use actix_web::{
    get, post, put,
    web::{Data, Json},
    HttpResponse,
};
use std::sync::RwLock;

#[derive(serde::Deserialize, Clone)]
pub struct AddPageData {
    parent_page_id: usize,
    new_page: Page,
}

#[post("/add-page")]
pub async fn add_page(
    website: Data<RwLock<WebSite>>,
    add_page_data: Json<AddPageData>,
) -> HttpResponse {
    let add_page_data = add_page_data.into_inner();
    match website
        .write()
        .expect("Couldn't acquire website write lock")
        .add_page(add_page_data.parent_page_id, add_page_data.new_page.clone())
    {
        Ok(()) => HttpResponse::Created().finish(),
        Err(msg) => {
            HttpResponse::BadRequest().body(format!("Error adding new page to website - {}", msg))
        }
    }
}

#[get("/page-data/{id}")]
pub async fn get_page_data(
    website: Data<RwLock<WebSite>>,
    id: actix_web::web::Path<usize>,
) -> HttpResponse {
    let id = id.into_inner();
    match website
        .read()
        .expect("Couldn't acquire website read lock")
        .get_page(id)
    {
        Some(page) => HttpResponse::Ok().json(page),
        None => HttpResponse::NotFound().body(format!("Page with id {} was not found", id)),
    }
}

#[put("/update-page/{id}")]
pub async fn update_page(
    id: actix_web::web::Path<usize>,
    website: Data<RwLock<WebSite>>,
    updated_page: Json<Page>,
) -> HttpResponse {
    let id = id.into_inner();

    match website
        .write()
        .expect("Couldn't acquire website write lock")
        .update_page(id, updated_page.into_inner())
    {
        Ok(page) => HttpResponse::Ok().json(page),
        Err(msg) => {
            HttpResponse::NotFound().body(format!("Error updating page with id {} - {:?}", id, msg))
        }
    }
}

#[post("/add-template")]
pub async fn add_template(
    website: Data<RwLock<WebSite>>,
    new_template: Json<PageTemplate>,
) -> HttpResponse {
    match website
        .write()
        .expect("Couldn't acquire website write lock")
        .add_template(new_template.into_inner())
    {
        Ok(template) => HttpResponse::Created().json(template),
        Err(msg) => HttpResponse::BadRequest().body(format!("Error adding new template {}", msg)),
    }
}

#[put("/update-template")]
pub async fn update_template(
    website: Data<RwLock<WebSite>>,
    updated_template: Json<PageTemplate>,
) -> HttpResponse {
    let updated = {
        let mut ws = website
            .write()
            .expect("Couldn't acquire website write lock");
        match ws.update_template(updated_template.into_inner()) {
            Ok(template) => template.clone(),
            Err(msg) => {
                return HttpResponse::BadRequest().body(format!("Error updating template {}", msg))
            }
        }
    };

    WebSite::update_page_rec_after_template_update(
        &mut website
            .write()
            .expect("Couldn't acquire website write lock")
            .root_page,
        &updated,
    );

    HttpResponse::Ok().json(updated)
}