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

use mysql_async::Pool;

use serde_json::{json, Value};

use std::collections::HashMap;

use db::{
    self,
    common::FromDB,
    channels::Channel
};

use crate::http::set_json_body;


pub async fn list_channels(pool: &Pool, response: &mut Response<Body>) {
    /*
     * @user-params -> for now none as i don't feel like dealing with it
     * @TODO: add in a let var that actually
    */
    return match  db::channels::Channel::filter(pool, 0).await {
        db::Response::Set(channels) => {
            set_json_body(response, json!(channels));
        },
        db::Response::Other(_msg) => *response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR,
        _ => *response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR,
    };
}

pub async fn create_channel(pool: &Pool, response: &mut Response<Body>, params: HashMap<&str, &str>) {
    /*
     * 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

    let name = params.get("name"); // str

    let description = if let Some(dval) = params.get("description") { // &str
        dval
    } else {
        "No description"
    };

    let kind = match params.get("kind") { // 1 for vc 2 for text
        Some(value) => {
            let v = *value;
            if let Ok(kval) = v.to_string().parse::<i32>() {
                Some(kval)
            } else {
                None
            }
        },
        None => None
    };

    match (name, kind) {
        (Some(name), Some(kind)) => {
            use db::channels::{TEXT_CHANNEL, VOICE_CHANNEL};
            if (kind == VOICE_CHANNEL) ^ (kind == TEXT_CHANNEL) {
                let db_resp = Channel::new(pool, name, description, kind).await;
                use db::Response::*;
                match db_resp {
                    Row(channel) => set_json_body(response, json!(channel)),
                    RestrictedInput(msg) => {
                        eprintln!("{}", msg);
                        *response.status_mut() = StatusCode::BAD_REQUEST;
                    },
                    Empty => *response.status_mut() = StatusCode::NOT_FOUND,
                    Other(msg) => {
                        *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
                        eprintln!("\t[ Channels ] {}", msg);
                    },
                    _ => *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR // ngmi
                };
            } else {
                *response.status_mut() = StatusCode::BAD_REQUEST; // restriciting to 1|2 for valid channel kinds
            }
        }
        _ => *response.status_mut() = StatusCode::BAD_REQUEST
    }
}

pub async fn delete_channel(pool: &Pool, response: &mut Response<Body>, params: Value) {
    // make sure we have the right parameters provided
    if let Some(name) = params.get("channel_id") {
        if let Some(id) = name.as_u64() {
            // TODO: something more intelligent with the logging im ngl
            match Channel::delete(pool, id).await {
                db::Response::Success => {},
                db::Response::Other(data) =>  {
                    eprintln!("\t{}", data);
                    *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
                }
                _ => {
                    eprintln!("\tBro like restart the server");
                    *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
                }
            }
        }
        else {
            *response.status_mut() = StatusCode::BAD_REQUEST;
        }
    }
    else {
        *response.status_mut() = StatusCode::BAD_REQUEST;
    }
}

