use poise::serenity_prelude as serenity; use super::autocomplete::trigger_name; use crate::Data; use crate::database; use crate::error::{Error, Result}; use crate::lang; type Context<'a> = poise::Context<'a, Data, Error>; /// Trigger keyword management #[poise::command( slash_command, guild_only, required_permissions = "MANAGE_GUILD", subcommands("create", "add", "remove", "delete", "list", "help",) )] pub async fn trigger(_ctx: Context<'_>) -> Result<()> { Ok(()) } /// Create a new trigger group #[poise::command(slash_command, guild_only)] pub async fn create( ctx: Context<'_>, #[description = "Logical group name"] #[autocomplete = "trigger_name"] name: String, ) -> Result<()> { let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; match database::create_trigger(&ctx.data().db_pool, guild_id.get() as i64, &name).await { Ok(_) => { ctx.data().reload_triggers().await; ctx.say(lang::fmt_trigger_created(&name)).await?; } Err(e) => { ctx.say(lang::fmt_trigger_failed(&e)).await?; } } Ok(()) } /// Add keywords and/or responses to a trigger group #[poise::command(slash_command, guild_only)] pub async fn add( ctx: Context<'_>, #[description = "Existing group name"] #[autocomplete = "trigger_name"] name: String, #[description = "Keywords separated by \\"] trigger_keywords: Option, #[description = "Responses separated by \\"] response: Option, ) -> Result<()> { let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; let t = database::get_trigger_by_name(&ctx.data().db_pool, guild_id.get() as i64, &name) .await? .ok_or_else(lang::err_trigger_not_found)?; let mut modified = false; if let Some(kw) = trigger_keywords { for keyword in kw.split('\\') { let k = keyword.trim(); if !k.is_empty() { database::add_keyword(&ctx.data().db_pool, t.id, k).await?; modified = true; } } } if let Some(r) = response { for resp in r.split('\\') { let r = resp.trim(); if !r.is_empty() { database::add_response(&ctx.data().db_pool, t.id, r).await?; modified = true; } } } if modified { ctx.data().reload_triggers().await; } ctx.say(lang::L_TRIGGER_UPDATED).await?; Ok(()) } /// Remove keyword or response from a group #[poise::command(slash_command, guild_only)] pub async fn remove( ctx: Context<'_>, #[description = "Group name"] #[autocomplete = "trigger_name"] name: String, #[description = "Keyword to remove"] trigger_keyword: Option, #[description = "Response to remove"] response: Option, ) -> Result<()> { let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; let t = database::get_trigger_by_name(&ctx.data().db_pool, guild_id.get() as i64, &name) .await? .ok_or_else(lang::err_trigger_not_found)?; let mut modified = false; if let Some(kw) = trigger_keyword { database::remove_keyword(&ctx.data().db_pool, t.id, &kw).await?; modified = true; } if let Some(r) = response { database::remove_response(&ctx.data().db_pool, t.id, &r).await?; modified = true; } if modified { ctx.data().reload_triggers().await; } ctx.say(lang::L_TRIGGER_UPDATED).await?; Ok(()) } /// Delete an entire trigger group #[poise::command(slash_command, guild_only)] pub async fn delete( ctx: Context<'_>, #[description = "Group name"] #[autocomplete = "trigger_name"] name: String, ) -> Result<()> { let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; let t = database::get_trigger_by_name(&ctx.data().db_pool, guild_id.get() as i64, &name) .await? .ok_or_else(lang::err_trigger_not_found)?; database::delete_trigger(&ctx.data().db_pool, t.id, guild_id.get() as i64).await?; ctx.data().reload_triggers().await; ctx.say(lang::fmt_trigger_deleted(&name)).await?; Ok(()) } /// List keywords and responses for a group #[poise::command(slash_command, guild_only)] pub async fn list( ctx: Context<'_>, #[description = "Group name"] #[autocomplete = "trigger_name"] name: String, ) -> Result<()> { let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; let t = database::get_trigger_by_name(&ctx.data().db_pool, guild_id.get() as i64, &name) .await? .ok_or_else(lang::err_trigger_not_found)?; let keywords = database::get_keywords(&ctx.data().db_pool, t.id).await?; let responses = database::get_responses(&ctx.data().db_pool, t.id).await?; let mut embed = serenity::CreateEmbed::default() .title(lang::fmt_trigger_title(&name)) .color(0x00aaff); embed = embed.field( "Keywords", if keywords.is_empty() { lang::L_TRIGGER_KW_NONE.into() } else { keywords .iter() .map(|r| r.to_string()) .collect::>() .join("\n") }, false, ); embed = embed.field( "Responses", if responses.is_empty() { lang::L_TRIGGER_KW_NONE.into() } else { responses .iter() .map(|r| r.to_string()) .collect::>() .join("\n") }, false, ); ctx.send(poise::CreateReply::default().embed(embed)).await?; Ok(()) } /// Display trigger command usage info #[poise::command(slash_command, guild_only)] pub async fn help(ctx: Context<'_>) -> Result<()> { let help = [ "**Trigger Commands**", "`/trigger create ` — Create new trigger group", "`/trigger add ` — Add keywords/responses (separate with \\)", "`/trigger remove ` — Remove keywords/responses", "`/trigger delete ` — Delete entire group", "`/trigger list ` — View group details", ] .join("\n"); ctx.say(help).await?; Ok(()) } pub fn commands() -> Vec> { vec![trigger()] }