use mysql_async::{params, Pool, Conn};
use mysql_async::prelude::Queryable;
use mysql_async::error::Error as SqlError;

use async_trait::async_trait;

use crate::Response;
use crate::{UBigInt, BigInt, Integer, VarChar};

use crate::common::{FromDB, NO_CONN_MSG};

pub struct Member {
    id: UBigInt,
    secret: VarChar,
    name: VarChar,
    joindate: BigInt,
    status: Integer,
    permissions: UBigInt,
}

/*
 *
 * conn = getconn
 * result = conn.query
 * return response based on result
 *
 */
#[async_trait]
impl FromDB<Member> for Member {
    type Row = Option<(VarChar, VarChar, BigInt, Integer, UBigInt)>;

    async fn get(p: &Pool, id: UBigInt) -> Response<Self> {
        if let Ok(conn) = p.get_conn().await {
            let q = "SELECT secret, name, joindate, status, permissions FROM members WHERE id = :id";
            let db_res : Result<(Conn, Self::Row), SqlError> 
                        = conn.first_exec(q, params!{"id" => id}).await;
            if let Ok((_, row)) = db_res {
                match row {
                    Some(row) => Response::Row(Self {
                        id: id,
                        secret: row.0,
                        name: row.1,
                        joindate: row.2,
                        status: row.3,
                        permissions: row.4
                    }),
                    None => Response::Empty
                }
            }
            else {
                return Response::Other("Query failed in Trait Member::get");
            }
        }
        else {
            return Response::Other(NO_CONN_MSG);
        }
    }

    async fn update(p: &Pool, row: Member) -> Response<Self> {
        let q = r#"UPDATE members
                SET status = :status, permissions = :perms, name = :name
                WHERE id = :id"#;
        if let Ok(conn) = p.get_conn().await {
            match Member::get(p, row.id).await {
                Response::Row(_) => {
                    // update now
                    let db_result: Result<Conn, SqlError>
                        = conn.drop_exec(q, params!{
                            "id" => row.id,
                            "status" => row.status,
                            "name" => row.name,
                            "perms" => row.permissions
                        }).await;
                    match db_result {
                        Ok(_) => return Response::Success,
                        Err(_) => return Response::Other("Could not update yet entry was found")
                    }
                },
                Response::Empty => return Response::Empty,
                Response::Other(msg) => return Response::Other(msg),
                _ => return Response::Other("Magical failure")
            }
        }
        return Response::Other(NO_CONN_MSG);
    }
}
