use cfg_if::cfg_if;
use leptos::*;
use validator::Validate;
use crate::backend::data::{ApiResponse, ResProperty};
use crate::components::data_form::ForValidation;

cfg_if! { if #[cfg(feature = "ssr")] {
    use crate::backend::get_pool;

    pub async fn get_props(filter: Option<String>) -> Result<Vec<ResProperty>, ServerFnError> {
        let pool = get_pool().await?;
        let props = if let Some(f) = filter {
            sqlx::query_as::<_, ResProperty>(&format!("SELECT * FROM property WHERE {} ORDER BY id", f)).fetch_all(&pool).await?
        } else {
            sqlx::query_as::<_, ResProperty>("SELECT * FROM property ORDER BY id").fetch_all(&pool).await?
        };

        Ok(props)
    }

    pub async fn get_prop_by_id(id: i32) -> Result<ResProperty, ServerFnError> {
        let pool = get_pool().await?;
        let prop = sqlx::query_as::<_, ResProperty>("SELECT * FROM property WHERE id = $1")
            .bind(id)
            .fetch_one(&pool)
            .await?;

        Ok(prop)
    }
}}

#[server]
pub async fn get_properties() -> Result<ApiResponse<Vec<ResProperty>>, ServerFnError> {
    let props = get_props(None).await?;

    Ok(ApiResponse::Data(props))
}

#[server]
pub async fn get_active_properties() -> Result<ApiResponse<Vec<ResProperty>>, ServerFnError> {
    let props = get_props(Some("active = true".to_string())).await?;

    Ok(ApiResponse::Data(props))
}

#[server]
pub async fn create_property(property: ResProperty) ->Result<ApiResponse<()>, ServerFnError> {
    use crate::backend::get_pool;
    use crate::perm_check;

    perm_check!(is_admin);

    let pool = get_pool().await?;
    sqlx::query("INSERT INTO property(name, description, price, slot) VALUES($1, $2, $3, $4)")
        .bind(&property.name)
        .bind(&property.description)
        .bind(&property.price)
        .bind(&property.slot)
        .execute(&pool)
        .await?;

    Ok(ApiResponse::Data(()))
}

#[server]
pub async fn edit_property(property: ResProperty) -> Result<ApiResponse<()>, ServerFnError> {
    use crate::backend::get_pool;
    use crate::perm_check;

    perm_check!(is_admin);

    let pool = get_pool().await?;
    sqlx::query("UPDATE property SET name = $1, description = $2, price = $3, active = $4, slot = $5 WHERE id = $6")
        .bind(&property.name)
        .bind(&property.description)
        .bind(&property.price)
        .bind(property.active)
        .bind(&property.slot)
        .bind(property.id())
        .execute(&pool)
        .await?;

    Ok(ApiResponse::Data(()))
}

#[server]
pub async fn delete_property(id: i32) -> Result<ApiResponse<()>, ServerFnError> {
    use crate::backend::get_pool;
    use crate::perm_check;

    perm_check!(is_admin);

    let pool = get_pool().await?;
    sqlx::query("DELETE FROM property WHERE id = $1")
        .bind(id)
        .execute(&pool)
        .await?;

    Ok(ApiResponse::Data(()))
}

impl ForValidation for CreateProperty {
    fn entity(&self) -> &dyn Validate {
        &self.property
    }
}

impl ForValidation for EditProperty {
    fn entity(&self) -> &dyn Validate {
        &self.property
    }
}