use crate::consts::THEME_COLOR;
use poise::{serenity_prelude::CreateEmbed, CommandInteractionType, CreateReply};
use serenity::builder::CreateEmbedFooter;

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)
                                    .embed(CreateEmbed::new()
                                        .title("💾 Currently recording macro")
                                        .description(
                                            format!("{} commands already recorded. Please use `/macro finish` to end recording.", MACRO_MAX_COMMANDS),
                                        )
                                        .footer(
                                            CreateEmbedFooter::new(
                                                "Any commands performed during recording won't take any actual action- they are only captured for the macro"
                                            )
                                        )
                                        .color(*THEME_COLOR),
                                    ),
                            )
                            .await;
                    } else {
                        match RecordedCommand::from_context(app_ctx) {
                            Some(recorded) => {
                                command_macro.commands.push(recorded);

                                let _ = ctx
                                    .send(
                                        CreateReply::default().ephemeral(true).embed(
                                            CreateEmbed::new()
                                                .title("💾 Currently recording macro")
                                                .description(
                                                    "Command recorded. Use `/macro finish` to end recording.",
                                                )
                                                .footer(
                                                    CreateEmbedFooter::new(
                                                        "Any commands performed during recording won't take any actual action- they are only captured for the macro"
                                                    )
                                                )
                                                .color(*THEME_COLOR),
                                        ),
                                    )
                                    .await;
                            }

                            None => {
                                let _ = ctx
                                    .send(
                                        CreateReply::default().ephemeral(true).embed(
                                            CreateEmbed::new()
                                                .title("💾 Currently recording macro")
                                                .description(
                                                    "This command is not supported in macros, so it hasn't been recorded. Use `/macro finish` to end recording.",
                                                )
                                                .footer(
                                                    CreateEmbedFooter::new(
                                                        "Any commands performed during recording won't take any actual action- they are only captured for the macro"
                                                    )
                                                )
                                                .color(*THEME_COLOR),
                                        ),
                                    )
                                    .await;
                            }
                        }
                    }

                    return false;
                }
            }
        }
    }

    true
}

async fn check_self_permissions(ctx: Context<'_>) -> bool {
    let user_id = ctx.serenity_context().cache.current_user().id;
    let app_permissions = match ctx {
        Context::Application(app_ctx) => app_ctx.interaction.app_permissions,
        _ => None,
    };

    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()));

            if let Some(permissions) = app_permissions {
                return if permissions.send_messages()
                    && permissions.embed_links()
                    && manage_webhooks
                    && permissions.view_channel()
                {
                    true
                } else {
                    let _ = ctx
                        .send(CreateReply::default().content(format!(
                            "The bot appears to be missing some permissions:

{}     **View Channels**
{}     **Send Message**
{}     **Embed Links**
{}     **Manage Webhooks**

Please check the bot's roles, and any channel overrides. Alternatively, giving the bot \"Administrator\" will bypass permission checks",
                            if permissions.view_channel() { "✅" } else { "❌" },
                            if permissions.send_messages() { "✅" } else { "❌" },
                            if permissions.embed_links() { "✅" } else { "❌" },
                            if manage_webhooks { "✅" } else { "❌" },
                        )))
                        .await;

                    false
                };
            }

            manage_webhooks
        }

        None => true,
    }
}

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