use serenity::{
    all::{ActivityData, Context, EventHandler, OnlineStatus, Ready},
    async_trait,
};
use tracing::info;

pub struct Handler;

#[async_trait]
impl EventHandler for Handler {
    async fn ready(&self, context: Context, ready: Ready) {
        info!("{} ({}) is connected!", ready.user.tag(), ready.user.id);

        let http = &context.http;
        let version = ready.version;
        let gateway = http.get_bot_gateway().await.unwrap();
        let total = gateway.session_start_limit.total;
        let remaining = gateway.session_start_limit.remaining;
        info!(
            "Connected to the Discord API (version {version}) with {remaining}/{total} sessions remaining."
        );

        let guilds_len = ready.guilds.len();
        info!("Connected to {} guilds", guilds_len);
        context.set_presence(
            Some(ActivityData::listening(format!("void"))),
            OnlineStatus::Idle,
        );
    }

    async fn message(&self, ctx: Context, msg: serenity::all::Message) {
        if let Err(e) = crate::commands::level::process_message(&ctx, &msg).await {
            tracing::error!("Error processing message for leveling: {}", e);
        }
        if let Err(e) = crate::commands::utility::process_auto_response(&ctx, &msg).await {
            tracing::error!("Error processing message for auto-response: {}", e);
        }
        if let Err(e) = crate::commands::fun::handle_ai_chat(&ctx, &msg).await {
            tracing::error!("Error processing message for AI chat: {}", e);
        }
    }

    async fn guild_member_update(
        &self,
        ctx: Context,
        old: Option<serenity::all::Member>,
        new: Option<serenity::all::Member>,
        event: serenity::all::GuildMemberUpdateEvent,
    ) {
        // The `new` parameter is Option<Member>, but we can construct a Member from the event if needed,
        // or just use the event data. However, poise/serenity's event handler signature for guild_member_update
        // provides `old_if_available` and `new`.
        // Wait, checking serenity 0.12 docs or looking at the trait definition.
        // Let's check the trait definition in the file first or assume standard serenity 0.12 signature.
        // Standard serenity 0.12 `EventHandler`:
        // async fn guild_member_update(&self, ctx: Context, old_if_available: Option<Member>, new: Option<Member>, event: GuildMemberUpdateEvent)
        // Actually, `new` is `Option<Member>`? Let's check.
        // If `cache` is enabled, `new` might be populated.
        // But we can also construct a partial member from `event`.
        // Let's try to use `new` if available, or fetch it.

        if let Some(new_member) = new {
            if let Err(e) =
                crate::commands::level::on_guild_member_update(&ctx, &old, &new_member).await
            {
                tracing::error!("Error processing guild member update: {}", e);
            }
        } else {
            // If member is not in cache, we might need to fetch it or construct it.
            // For now, let's rely on cache or just fetch it.
            // The event has `user` and `roles`.
            // We can construct a Member-like object or just fetch the full member.
            if let Ok(member) = ctx.http.get_member(event.guild_id, event.user.id).await {
                if let Err(e) =
                    crate::commands::level::on_guild_member_update(&ctx, &old, &member).await
                {
                    tracing::error!("Error processing guild member update: {}", e);
                }
            }
        }
    }
}
