use parking_lot;

use serenity;
use serenity::client::CACHE;
use serenity::model::id::{ChannelId, GuildId};
use serenity::voice::Handler;

use super::prelude::*;

pub fn guild_id(channel_id: ChannelId) -> Option<GuildId> {
    match CACHE.read().guild_channel(channel_id) {
        Some(channel) => Some(channel.read().guild_id),
        None => {
            print_error!(channel_id.say("Error finding channel info"));
            None
        }
    }
}

pub fn handler<'a>(
    guild_id: GuildId,
    manager: &'a mut parking_lot::MutexGuard<
        '_,
        serenity::client::bridge::voice::ClientVoiceManager,
    >,
) -> Option<&'a mut Handler> {
    manager.get_mut(guild_id)
}

pub fn channel_contains_author(
    ctx: &mut serenity::client::Context,
    msg: &serenity::model::channel::Message,
) -> bool {
    let (guild_id, voice_channel_id_bot) = {
        match ctx.data.lock().get::<VoiceManager>().cloned() {
            Some(manager_lock) => {
                let mut manager = manager_lock.lock();
                let guild_id = match guild_id(msg.channel_id) {
                    Some(guild_id) => guild_id,
                    None => {
                        println!("error getting guild_id");
                        return true;
                    }
                };

                let handler = match handler(guild_id, &mut manager) {
                    Some(handler) => handler,
                    None => {
                        println!("error getting handler");
                        return true;
                    }
                };

                (
                    guild_id,
                    match handler.channel_id {
                        Some(id) => id,
                        None => {
                            println!("error getting channel_id for bot");
                            return true;
                        }
                    },
                )
            }
            None => return false,
        }
    };

    let author = &msg.author;

    let guild = match guild_id.to_guild_cached() {
        Some(guild) => guild,
        None => {
            println!("error getting guild from cache");
            return true;
        }
    };

    let guild_lock = guild.read();

    let voice_state = match guild_lock.voice_states.get(&author.id) {
        Some(state) => state,
        None => {
            println!("error getting voice state from user {}", author.name);
            return false;
        }
    };

    if let Some(voice_channel_id_user) = voice_state.channel_id {
        if voice_channel_id_bot != voice_channel_id_user {
            return false;
        }
    }

    true
}