use sqlx::error::Error;
use sqlx::sqlite::{SqlitePool, SqliteRow};
use sqlx_core::row::Row;

use crate::model::user::User;

pub async fn list(pool: &SqlitePool) -> Vec<User> {
    let res = sqlx::query_as::<_, User>(
        r#"
SELECT
    id,
    name,
    email
FROM
    users
ORDER BY
    name
    "#,
    )
    .fetch_all(pool)
    .await;

    match res {
        Ok(users) => users,
        Err(err) => {
            error!("Error listing users: {:?}", err);
            vec![]
        }
    }
}

pub async fn set_login_token(
    pool: &SqlitePool,
    email: String,
    login_token: String,
) -> bool {
    let res = sqlx::query(
        r#"
UPDATE
    users
SET
    login_token = ?,
    updated_at = datetime()
WHERE
    email = ?
    "#,
    )
    .bind(login_token)
    .bind(email)
    .execute(pool)
    .await;

    match res {
        Ok(_) => true,
        Err(err) => {
            error!("Error updating login token: {:?}", err);
            false
        }
    }
}

pub async fn remove_login_token(pool: &SqlitePool, id: i64) -> bool {
    let res = sqlx::query(
        r#"
UPDATE
    users
SET
    login_token = NULL,
    updated_at = datetime()
WHERE
    id = ?
    "#,
    )
    .bind(id)
    .execute(pool)
    .await;

    match res {
        Ok(_) => true,
        Err(err) => {
            error!("Error removing login token: {:?}", err);
            false
        }
    }
}

pub async fn get_by_login_token(
    pool: &SqlitePool,
    login_token: String,
) -> Option<User> {
    let res = sqlx::query_as::<_, User>(
        r#"
SELECT
    id, 
    name,
    email
FROM
    users
WHERE
    login_token = ?
    "#,
    )
    .bind(login_token)
    .fetch_one(pool)
    .await;

    match res {
        Ok(user) => Some(user),
        Err(Error::RowNotFound) => None,
        Err(err) => {
            error!("Error getting user from login token: {:?}", err);
            None
        }
    }
}

pub async fn get_password_hash(
    pool: &SqlitePool,
    email: String,
) -> Option<String> {
    let res = sqlx::query(
        r#"
SELECT
    password
FROM
    users
WHERE
    email = ?
    "#,
    )
    .bind(email)
    .map(|row: SqliteRow| row.get("password"))
    .fetch_one(pool)
    .await;

    match res {
        Ok(hash) => Some(hash),
        Err(Error::RowNotFound) => None,
        Err(err) => {
            error!("Error getting password hash: {:?}", err);
            None
        }
    }
}