#![allow(non_snake_case)]

extern crate serenity;

extern crate parking_lot;
extern crate serde_json;
extern crate typemap;

mod player;

use serenity::{
    framework::standard::{
        help_commands,
        macros::{group, help},
        Args, CommandGroup, CommandResult, HelpOptions, StandardFramework,
    },
    model::{channel::Message, id::UserId},
};

// This imports `typemap`'s `Key` as `TypeMapKey`.
use serenity::prelude::*;

use std::sync::{Arc, Mutex};

use player::prelude::*;
use std::collections::HashSet;

use utilities::prelude::*;

create_settings_section!(
    Config,
    "Meta",
    {
        token: String,
        prefix: String,
        volume: f32,
    },
);

#[group]
#[commands(ip, list, pause, play, remove, skip, stop, tag)]
struct General;

#[help]
fn my_help(
    context: &mut Context,
    msg: &Message,
    args: Args,
    help_options: &'static HelpOptions,
    groups: &[&'static CommandGroup],
    owners: HashSet<UserId>,
) -> CommandResult {
    help_commands::with_embeds(context, msg, args, &help_options, groups, owners)
}

fn main() -> VerboseResult<()> {
    // read config file
    let config_file = ConfigHandler::read_config("bot.conf")?;

    let config = Config::load(&config_file)?;

    let mut client = Client::new(&config.token, Handler).expect("Err creating client");

    let media_data = Arc::new(Mutex::new(
        MediaData::new("Penis1", Arc::clone(&client.voice_manager), config.volume)
            .expect("failed to create media data handle"),
    ));

    // Obtain a lock to the data owned by the client, and insert the client's
    // voice manager into it. This allows the voice manager to be accessible by
    // event handlers and framework commands.
    {
        let mut data = client.data.write();
        data.insert::<Media>(media_data.clone());
    }

    // We will fetch your bot's owners and id
    let (owners, bot_id) = match client.cache_and_http.http.get_current_application_info() {
        Ok(info) => {
            let mut owners = HashSet::new();
            owners.insert(info.owner.id);

            (owners, info.id)
        }
        Err(why) => panic!("Could not access application info: {:?}", why),
    };

    client.with_framework(
        // Configures the client, allowing for options to mutate how the
        // framework functions.
        //
        // Refer to the documentation for
        // `serenity::ext::framework::Configuration` for all available
        // configurations.
        StandardFramework::new()
            .configure(|c| {
                c.with_whitespace(true)
                    .on_mention(Some(bot_id))
                    .prefix(&config.prefix)
                    .owners(owners)
            })
            .group(&GENERAL_GROUP)
            .help(&MY_HELP),
    );

    let _ = client
        .start()
        .map_err(|why| println!("Client ended: {:?}", why));

    Ok(())
}
