use serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool};

#[derive(FromRow, Debug, Serialize, Deserialize)]
pub struct Location {
    pub id: i64,
    pub name: String,
}

impl Location {
    pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option<Self> {
        sqlx::query_as!(
            Self,
            "
    SELECT id, name
    FROM location
    WHERE id like ?
            ",
            id
        )
        .fetch_one(db)
        .await
        .ok()
    }

    pub async fn find_by_name(db: &SqlitePool, name: String) -> Option<Self> {
        sqlx::query_as!(
            Self,
            "
    SELECT id, name
    FROM location
    WHERE name=?
            ",
            name
        )
        .fetch_one(db)
        .await
        .ok()
    }

    pub async fn all(db: &SqlitePool) -> Vec<Self> {
        sqlx::query_as!(Self, "SELECT id, name FROM location")
            .fetch_all(db)
            .await
            .unwrap() //TODO: fixme
    }

    pub async fn create(db: &SqlitePool, name: &str) -> bool {
        sqlx::query!("INSERT INTO location(name) VALUES (?)", name)
            .execute(db)
            .await
            .is_ok()
    }

    pub async fn delete(&self, db: &SqlitePool) {
        sqlx::query!("DELETE FROM location WHERE id=?", self.id)
            .execute(db)
            .await
            .unwrap(); //Okay, because we can only create a Location of a valid id
    }
}

#[cfg(test)]
mod test {
    use crate::{model::location::Location, testdb};

    use sqlx::SqlitePool;

    #[sqlx::test]
    fn test_find_correct_id() {
        let pool = testdb!();
        let location = Location::find_by_id(&pool, 1).await.unwrap();
        assert_eq!(location.id, 1);
    }

    #[sqlx::test]
    fn test_find_wrong_id() {
        let pool = testdb!();
        let location = Location::find_by_id(&pool, 1337).await;
        assert!(location.is_none());
    }

    #[sqlx::test]
    fn test_all() {
        let pool = testdb!();
        let res = Location::all(&pool).await;
        assert!(res.len() > 1);
    }

    #[sqlx::test]
    fn test_succ_create() {
        let pool = testdb!();

        assert_eq!(Location::create(&pool, "new-loc-name".into(),).await, true);
    }

    #[sqlx::test]
    fn test_duplicate_name_create() {
        let pool = testdb!();

        assert_eq!(Location::create(&pool, "Linz".into(),).await, false);
    }
}
