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::{VarChar, UBigInt, Integer};
use crate::common::FromDB;
use crate::{sql_err, no_conn, Response};

#[allow(dead_code)]
pub struct Channel {
    pub id: UBigInt,
    pub name: VarChar,
    pub description: Option<VarChar>,
    pub kind: Integer
}

#[async_trait]
impl FromDB<Channel> for Channel {
    // id name desc kind
    type Row = Option<(UBigInt, VarChar, Option<VarChar>, Integer)>;

    async fn get(p: &Pool, id: UBigInt) -> Response<Channel> {
        //! Retrieves a Full single Channel row from the DB or fails in a 
        //! fashion described by crate::Response<Channel>
        //! @param p -> SqlPool
        //! @param id -> UBigInt
        //! @return on_success -> Response::Row(Channel)
        //! @return on_fail -> Response::{Empty, Other<String>}
        if let Ok(conn) = p.get_conn().await {
            let q = "SELECT id, name, description, kind FROM channels WHERE id = :id";
            let result: Result<(Conn, Self::Row), SqlError> = 
                conn.first_exec(q, params!{"id" => id}).await;
            if let Ok((_, row)) = result {
                return match row {
                    Some(row) => Response::Row(Channel {
                        id: id,
                        name: row.1,
                        description: row.2,
                        kind: row.3

                    }),
                    None => Response::Empty
                }
            }
            return Response::Other(no_conn!("Invite::FromDB::get fetch failed"));
        }
        return Response::Other(no_conn!("Invite::FromDB::get"));
    }

    async fn update(p: &Pool, row: Self) -> Response<Channel> {
        //! Updates a whole single based on a given Row Of Channel Type
        //! @param p -> SqlPool
        //! @param row -> Channel
        //! @return on_success -> Response::Success
        //! @return on_failure -> Response::Other
        if let Ok(conn) = p.get_conn().await {
            let q = "UPDATE channels
                SET name = :name, description = :desc, kind = :kind 
                WHERE id = :id";
            let result: Result<Conn, SqlError> =
                conn.drop_exec(q, params!{
                    "id" => row.id,
                    "name" => row.name,
                    "desc" => row.description,
                    "kind" => row.kind
                }).await;
            return match result {
                Ok(_) => Response::Success,
                Err(_) => Response::Other(sql_err!("Invite::FromDB::update Update failed"))
            }
        }
        return Response::Other(no_conn!("Invite::FromDB::get connection failed"));
    }

    async fn delete(p: &Pool, id: UBigInt) -> Response<Channel> {
        //! Deletes channel given UBigInt as the row key
        //! @param p -> SqlPool
        //! @param id -> UBigInt
        //! @return on_success -> Response::Success
        //! @return on_failure -> Response::Other
        if let Ok(conn) = p.get_conn().await {
            let q = "DELETE FROM channels WHERE id = :id";
            let result: Result<Conn, SqlError> = 
                conn.drop_exec(q, params!{"id" => id}).await;
            return match result {
                Ok(_) => Response::Success,
                Err(_) => Response::Other(sql_err!("Member::FromDB::delete Listen i dont know either"))
            }
        }
        return Response::Other(no_conn!("Member::FromDB::delete"))
    }
}
