use hyper::{StatusCode, Response, Body};

use mysql_async::Pool;

use serde_json::json;

use std::collections::HashMap;

use db::{ self, Channel};

use crate::http::set_json_body;
use crate::qs_param;


pub async fn list_channels(pool: &Pool, response: &mut Response<Body>, params: HashMap<String, String>) {
    /*
     * @user-params -> for now none as i don't feel like dealing with it
    */

    // Default to filtering for text channels only
    let chan_type = match qs_param!(params, "kind", i32) {
        Some(ctype) => ctype,
        None => db::channels::TEXT_CHANNEL
    };

    match db::Channel::filter(pool, chan_type).await {
        Ok(resp) => match resp {
            db::Response::Set(channels) => set_json_body(response, json!({"channels": json!(channels)}) ),
            _ => *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR
        },
        Err(e) => {
            *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
            eprintln!("{}", e);
        }
    }
}

pub async fn create_channel(pool: &Pool, response: &mut Response<Body>, params: HashMap<String, String>) {
    /*
     * Create a channel base on a few parameters that may or may not be there
     * @responds with the data of the newly created channel
    */
    // Theres an extra un-needed unwrap to be cut out from this proc
    // specifically with the desc parameter
    use db::Response::*;

    let name = params.get("name");
    let kind = qs_param!(params, "kind", i32);
    let description = match params.get("description") {
        Some(d) => d,
        None => "No description"
    };

    *response.status_mut() = if name.is_some() && kind.is_some() {
        let (name, kind) = (name.unwrap(), kind.unwrap());

        if let Ok(resp) = Channel::add(pool, name, description, kind).await { 
            match resp {
                Row(channel) => {
                    set_json_body(response, json!(channel));
                    StatusCode::OK
                },

                RestrictedInput(_) => StatusCode::UNPROCESSABLE_ENTITY,
                Other(_) => StatusCode::INTERNAL_SERVER_ERROR,
                _ => StatusCode::INTERNAL_SERVER_ERROR
            }
        } else {
            StatusCode::INTERNAL_SERVER_ERROR
        }
    } else {
        StatusCode::BAD_REQUEST
    }
}

pub async fn delete_channel(pool: &Pool, response: &mut Response<Body>, params: HashMap<String, String>) {
    /*
     * Deletes a channel from the database, only after making sure the user has
     * the required permissions to do so
     * @channel_id : u64 - required
    */
    use crate::perms;
    use db::Member;
    use db::Response::*;

    let uid = qs_param!(params, "id", u64).unwrap();
    let permissions = match Member::get(pool, uid).await {
        Row(user) => user.permissions,
        _ => 0
    };

    // make sure unpriveleged users don't delete channels somehow
    if perms::has_perm(permissions, perms::DELETE_CHANNEL) == false{
        *response.status_mut() = StatusCode::BAD_REQUEST;
        return;
    }

    // Collect the channel_id param before we attempt deletion
    let channel_id = if let Some(chan) = params.get("channel_id") {
        let c = chan;
        match c.to_string().parse::<u64>() {
            Ok(val) => Some(val),
            _ => None
        }
    } else {
        None
    };

    if let Some(id) = channel_id {
        match Channel::delete(pool, id).await {
            Success => {/* nothing to do on sucess */},
            Other(data) =>  {
                eprintln!("\t{}", data);
                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
            }
            _ => { // ngmi
                eprintln!("\tBro like restart the server this branch should never execute");
                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
            }
        }     
    }
    else {
        *response.status_mut() = StatusCode::BAD_REQUEST;
    }
}

