use cfg_if::cfg_if;
use leptos::{server, ServerFnError};
use crate::backend::data::ApiResponse;
use crate::backend::data::Customer;

cfg_if! { if #[cfg(feature = "ssr")] {
    use sqlx::{Postgres, Transaction};
    use sqlx::{query_as, query};
    use sqlx::Error;
    use std::ops::DerefMut;
    use leptos::expect_context;
    use leptos_actix::extract;
    use actix_session::Session;

    pub async fn find_customer_by_email(email: &str, tx: &mut Transaction<'_, Postgres>) -> Option<Customer> {
        let customer = query_as::<_, Customer>("SELECT * FROM customer WHERE email = $1")
            .bind(email)
            .fetch_one(tx.deref_mut())
            .await.unwrap_or_default();

        if customer.email == email {
            Some(customer)
        } else {
            None
        }
    }

    pub async fn sync_customer_data(customer: &Customer, full_name: &str, phone: &str, tx: &mut Transaction<'_, Postgres>) -> Result<Customer, Error> {
        if &customer.full_name != full_name || &customer.phone != phone {
            query("UPDATE CUSTOMER SET full_name=$1, phone=$2 WHERE id=$3")
                .bind(full_name)
                .bind(phone)
                .bind(customer.id())
                .execute(tx.deref_mut())
                .await?;
            Ok(Customer::new(customer.id(),
                full_name.to_string(),
                customer.email.clone(),
                phone.to_string(),
                customer.discount))
        } else {
            Ok(customer.clone())
        }
    }

    pub async fn create_customer(full_name: &str, email: &str, phone: &str, tx: &mut Transaction<'_, Postgres>) -> Result<Customer, Error> {
        query("INSERT INTO customer(full_name, email, phone) VALUES($1, $2, $3)")
            .bind(full_name)
            .bind(email)
            .bind(phone)
            .execute(tx.deref_mut())
            .await?;
        Ok(find_customer_by_email(email, tx).await.ok_or(Error::RowNotFound)?)
    }

    pub async fn remember_customer(customer: Customer) -> Result<(), ServerFnError> {
        let session: Session = extract().await?;
        session.insert("customer", customer)?;
        Ok(())
    }
}}

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

    perm_check!(is_logged_in);

    let pool = get_pool().await?;

    let customers = query_as::<_, Customer>("SELECT * FROM customer")
        .fetch_all(&pool)
        .await?;

    Ok(ApiResponse::Data(customers))
}

#[server]
pub async fn get_remembered() -> Result<Option<Customer>, ServerFnError> {
    use actix_session::*;
    use leptos_actix::extract;

    let session = extract::<Session>().await;

    if session.is_err() {
        return Ok(None);
    }

    Ok(session.unwrap().get::<Customer>("customer").unwrap_or(None))
}