use log::{error, info};
use serde::{Deserialize, Serialize};
use sqlx::{Arguments, AssertSqlSafe, Decode, Encode, FromRow, PgPool, Row};
use sqlx::postgres::{PgArguments, PgRow};

#[derive(Debug, Deserialize, Serialize, Clone, FromRow, Decode, Encode)]
pub struct Settings {
    pub id: i64,
    pub mhd: String,
    pub bio: String,
    pub allergens_text: String,
    pub bio_info: String,
}

fn from_postgres_row_small(row: PgRow) -> Settings {
    Settings {
        id: row.get(0),
        mhd: row.get(1),
        bio: row.get(2),
        allergens_text: row.get(3),
        bio_info: row.get(4),
    }
}

pub async fn load_settings(pool: &PgPool) -> Option<Settings> {
    let statement = format!(
        "SELECT * FROM {}",
        "settings",
    );

    let res = sqlx::query(
        AssertSqlSafe(statement.as_str()))
        .fetch_one(pool).await;

    match res {
        Ok(record) => {
            Some(from_postgres_row_small(record))
        }
        Err(err) => {
            error!("Error while loading settings.");
            None
        }
    }
}

pub async fn update_settings(settings: &Settings, pool: PgPool) -> Option<Settings> {
    let mut args = PgArguments::default();
    args.add(&settings.id);
    args.add(&settings.mhd);
    args.add(&settings.bio);
    args.add(&settings.allergens_text);
    args.add(&settings.bio_info);

    let statement = format!(
        "UPDATE {} SET mhd = $2, bio = $3, allergens_text = $4, bio_info = $5 WHERE id = $1 RETURNING *",
        "settings",
    );

    let res = sqlx::query_with(
        AssertSqlSafe(statement.as_str()),
        args)
        .fetch_one(&pool).await;

    info!("{:#?}", res);

    match res {
        Ok(record) => {
            let label = from_postgres_row_small(record);
            Some(label)
        }
        Err(err) => {
            error!("Error while updating settings.");
            None
        }
    }
}
