use super::*;
use schema::{
    farm_entry::dsl::{date as farm_entry_date, farm_entry},
    user::dsl::{id as user_id, ignored, user},
    user_farm::dsl::user_farm,
};
use serenity::{
    framework::standard::{macros::command, CommandError, CommandResult},
    model::{
        guild::Member,
        id::{ChannelId, GuildId},
    },
};

#[command]
#[aliases("no")]
#[description = "List all users who farm nothing from a date, default to last Friday"]
#[usage = "[-f]\n    -f DATE   # set from date in format yyyy-mm-dd"]
#[example = "-f 2019-01-01"]
#[only_in("guilds")]
pub fn nothing(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
    let roles = &msg.mention_roles;
    let send_dm = args.message().contains("-dm");

    let date = get_from_date(args.clone())?;

    let conn = establish_connection();

    let users_ids: Vec<i32> = get_user_for_roles(ctx, roles, msg.guild_id.unwrap())?
        .iter()
        .map(|u| u.id)
        .collect();

    let farms = user
        .left_join(user_farm.left_join(farm_entry))
        .select(user_id)
        .distinct()
        .filter(farm_entry_date.ge(date.naive_utc()));

    let no_farm_users: Vec<User> = user
        .filter(
            user_id
                .ne_all(farms)
                .and(user_id.eq_any(users_ids))
                .and(ignored.eq(false)),
        )
        .load(&conn)?;

    if send_dm {
        loop {
            let arg: String = args.single()?;

            if arg == "-dm" {
                break;
            }
        }

        send_dm_message(
            ctx,
            &no_farm_users,
            msg.guild_id.unwrap(),
            msg.channel_id,
            args.rest().to_string(),
        )?;
    }

    let reply = format!(
        "```asciidoc\nUser without farm announced since {}\n============================================\n{}```",
        date.naive_utc().date(),
        no_farm_users.iter().map(|u| u.discord_username.clone()).collect::<Vec<String>>().join("\n")
    );
    msg.channel_id.say(ctx, reply)?;

    Ok(())
}

fn send_dm_message(
    ctx: &mut Context,
    users: &[User],
    guild: GuildId,
    channel: ChannelId,
    txt: String,
) -> CommandResult {
    let user_ids: Vec<u64> = users.iter().map(|u| u.discord_id).collect();

    let members: Vec<Member> = guild.members(&ctx, Some(1000), None)?;
    let filtered: Vec<&Member> = members
        .iter()
        .filter(|m: &&Member| user_ids.contains(&m.user_id().0))
        .collect();

    for m in filtered {
        debug!("Send DM to{:?}", m);
        m.user_id()
            .create_dm_channel(&ctx)?
            .send_message(&ctx, |m| m.content(txt.clone()))
            .map_err(|e| CommandError(e.to_string()))?;
    }

    channel.say(
        &ctx,
        format!(
            "Send '{}' in dm to {:?}",
            txt,
            users
                .iter()
                .map(|u| u.discord_username.clone())
                .collect::<Vec<String>>()
        ),
    )?;

    Ok(())
}
