use poise::{serenity_prelude::model::channel::Channel, CommandInteractionType, CreateReply};

use crate::{consts::MACRO_MAX_COMMANDS, models::command_macro::RecordedCommand, Context, Error};

async fn macro_check(ctx: Context<'_>) -> bool {
    if let Context::Application(app_ctx) = ctx {
        if app_ctx.interaction_type != CommandInteractionType::Command {
            return true;
        }

        if let Some(guild_id) = ctx.guild_id() {
            if ctx.command().identifying_name != "finish_macro" {
                let mut lock = ctx.data().recording_macros.write().await;

                if let Some(command_macro) = lock.get_mut(&(guild_id, ctx.author().id)) {
                    if command_macro.commands.len() >= MACRO_MAX_COMMANDS {
                        let _ = ctx
                            .send(
                                CreateReply::default()
                                    .ephemeral(true)
                                    .content(format!("{} commands already recorded. Please use `/macro finish` to end recording.", MACRO_MAX_COMMANDS))
                            )
                            .await;
                    } else {
                        match RecordedCommand::from_context(app_ctx) {
                            Some(recorded) => {
                                command_macro.commands.push(recorded);

                                let _ = ctx
                                    .send(
                                        CreateReply::default()
                                            .ephemeral(true)
                                            .content("Command recorded to macro"),
                                    )
                                    .await;
                            }

                            None => {
                                let _ = ctx
                                    .send(
                                        CreateReply::default().ephemeral(true).content(
                                            "This command is not supported in macros yet.",
                                        ),
                                    )
                                    .await;
                            }
                        }
                    }

                    return false;
                }
            }
        }
    }

    true
}

async fn check_self_permissions(ctx: Context<'_>) -> bool {
    let user_id = ctx.serenity_context().cache.current_user().id;

    match ctx.guild().map(|g| g.to_owned()) {
        Some(guild) => {
            let manage_webhooks = guild
                .member(&ctx, user_id)
                .await
                .map_or(false, |m| m.permissions(&ctx).map_or(false, |p| p.manage_webhooks()));

            let (view_channel, send_messages, embed_links) = ctx
                .channel_id()
                .to_channel(&ctx)
                .await
                .ok()
                .and_then(|c| {
                    if let Channel::Guild(channel) = c {
                        let perms = channel.permissions_for_user(&ctx, user_id).ok()?;

                        Some((perms.view_channel(), perms.send_messages(), perms.embed_links()))
                    } else {
                        None
                    }
                })
                .unwrap_or((false, false, false));

            if manage_webhooks && send_messages && embed_links {
                true
            } else {
                let _ = ctx
                    .send(CreateReply::default().content(format!(
                        "Please ensure the bot has the correct permissions:

{}     **View Channel**
{}     **Send Message**
{}     **Embed Links**
{}     **Manage Webhooks**",
                        if view_channel { "✅" } else { "❌" },
                        if send_messages { "✅" } else { "❌" },
                        if embed_links { "✅" } else { "❌" },
                        if manage_webhooks { "✅" } else { "❌" },
                    )))
                    .await;

                false
            }
        }

        None => {
            return true;
        }
    }
}

pub async fn all_checks(ctx: Context<'_>) -> Result<bool, Error> {
    Ok(macro_check(ctx).await && check_self_permissions(ctx).await)
}
