stats channels
diff --git a/src/events/guildBanAdd.ts b/src/events/guildBanAdd.ts
index 64a1604..d095049 100644
--- a/src/events/guildBanAdd.ts
+++ b/src/events/guildBanAdd.ts
@@ -1,5 +1,5 @@
 import { purgeByUser } from '../actions/tickets/delete.js';
-import { callback as statsChannelRemove } from '../reflex/statsChannelRemove.js';
+import { callback as statsChannelRemove } from '../reflex/statsChannelUpdate.js';
 
 export const event = 'guildBanAdd';
 
diff --git a/src/events/guildBanRemove.ts b/src/events/guildBanRemove.ts
index a6d1c14..4d6d1f8 100644
--- a/src/events/guildBanRemove.ts
+++ b/src/events/guildBanRemove.ts
@@ -1,6 +1,6 @@
 import humanizeDuration from 'humanize-duration';
 import { purgeByUser } from '../actions/tickets/delete.js';
-import { callback as statsChannelRemove } from '../reflex/statsChannelRemove.js';
+import { callback as statsChannelRemove } from '../reflex/statsChannelUpdate.js';
 
 export const event = 'guildBanRemove';
 
diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts
index 1fd1e1f..900c774 100644
--- a/src/events/interactionCreate.ts
+++ b/src/events/interactionCreate.ts
@@ -3,18 +3,43 @@
 import create from "../actions/tickets/create.js";
 import close from "../actions/tickets/delete.js";
 import createTranscript from "../premium/createTranscript.js";
+import Fuse from "fuse.js";
+import { autocomplete as tagAutocomplete } from "../commands/tag.js"
 
 export const event = 'interactionCreate';
 
+
+function getAutocomplete(typed: string, options: string[]): object[] {
+    options = options.filter(option => option.length <= 100) // thanks discord. 6000 character limit on slash command inputs but only 100 for autocomplete.
+    if (!typed) return options.slice(0, 25).sort().map(option => ({name: option, value: option}))
+    const fuse = new Fuse(options, {useExtendedSearch: true, findAllMatches: true, minMatchCharLength: 0}).search(typed)
+    return fuse.slice(0, 25).map(option => ({name: option.item, value: option.item}))
+}
+
+const validReplacements = ["serverName", "memberCount", "memberCount:bots", "memberCount:humans"]
+function generateStatsChannelAutocomplete(typed) {
+    let autocompletions = []
+    const beforeLastOpenBracket = typed.match(/(.*){[^{}]{0,15}$/)
+    if (beforeLastOpenBracket !== null) { for (let replacement of validReplacements) { autocompletions.push(`${beforeLastOpenBracket[1]} {${replacement}}`) } }
+    else { for (let replacement of validReplacements) { autocompletions.push(`${typed} {${replacement}}`) } }
+    return getAutocomplete(typed, autocompletions)
+}
+
 async function interactionCreate(interaction) {
     if (interaction.componentType === "BUTTON") {
-        if (interaction.customId === "rolemenu") return await roleMenu(interaction)
-        if (interaction.customId === "verifybutton") return verify(interaction)
-        if (interaction.customId === "createticket") return create(interaction)
-        if (interaction.customId === "closeticket") return close(interaction)
-        if (interaction.customId === "createtranscript") return createTranscript(interaction)
+        switch (interaction.customId) {
+            case "rolemenu": { return await roleMenu(interaction) }
+            case "verifybutton": { return verify(interaction) }
+            case "createticket": { return create(interaction) }
+            case "closeticket": { return close(interaction) }
+            case "createtranscript": { return createTranscript(interaction) }
+        }
     } else if (interaction.componentType === "MESSAGE_COMPONENT") {
-        console.table(interaction)
+    } else if (interaction.type === "APPLICATION_COMMAND_AUTOCOMPLETE") {
+        switch (`${interaction.commandName} ${interaction.options.getSubcommandGroup(false)} ${interaction.options.getSubcommand(false)}`) {
+            case `tag null null`: { return interaction.respond(getAutocomplete(interaction.options.getString("tag"), (await tagAutocomplete(interaction)))) }
+            case `settings stats set`: { return interaction.respond(generateStatsChannelAutocomplete(interaction.options.getString("name"))) }
+        }
     }
 }
 
diff --git a/src/events/memberJoin.ts b/src/events/memberJoin.ts
index b1c2700..7bee084 100644
--- a/src/events/memberJoin.ts
+++ b/src/events/memberJoin.ts
@@ -1,4 +1,4 @@
-import { callback as statsChannelAdd } from '../reflex/statsChannelAdd.js';
+import { callback as statsChannelAdd } from '../reflex/statsChannelUpdate.js';
 import { callback as welcome } from '../reflex/welcome.js';
 import log from '../utils/log.js';
 import client from '../utils/client.js';
@@ -7,7 +7,6 @@
 
 export async function callback(_, member) {
     try { welcome(_, member); } catch {}
-    try { statsChannelAdd(_, member); } catch {}
     try {
         const { log, NucleusColors, entry, renderUser, renderDelta } = member.client.logger
         try { await client.database.history.create("join", member.guild.id, member.user, null, null) } catch {}
@@ -33,4 +32,5 @@
         }
         log(data);
     } catch {}
+    try { statsChannelAdd(_, member, ); } catch {}
 }
diff --git a/src/events/memberLeave.ts b/src/events/memberLeave.ts
index 592a630..122e01a 100644
--- a/src/events/memberLeave.ts
+++ b/src/events/memberLeave.ts
@@ -1,11 +1,10 @@
 import humanizeDuration from 'humanize-duration';
 import { purgeByUser } from '../actions/tickets/delete.js';
-import { callback as statsChannelRemove } from '../reflex/statsChannelRemove.js';
+import { callback as statsChannelRemove } from '../reflex/statsChannelUpdate.js';
 
 export const event = 'guildMemberRemove'
 
 export async function callback(client, member) {
-    try { await statsChannelRemove(client, member); } catch {}
     try { purgeByUser(member.id, member.guild); } catch {}
     try {
         const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta } = member.client.logger
@@ -72,4 +71,5 @@
         }
         log(data);
     } catch (e) { console.log(e) }
+    try { await statsChannelRemove(client, member); } catch {}
 }
diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts
index 7db7d39..dce1959 100644
--- a/src/events/messageCreate.ts
+++ b/src/events/messageCreate.ts
@@ -1,7 +1,6 @@
 import { LinkCheck, MalwareCheck, NSFWCheck, SizeCheck, TestString, TestImage } from '../reflex/scanners.js'
 import logAttachment from '../premium/attachmentLogs.js'
 import createLogException from '../utils/createLogException.js'
-import { capitalize } from '../utils/generateKeyValueList.js'
 import getEmojiByName from '../utils/getEmojiByName.js'
 
 export const event = 'messageCreate'
@@ -19,7 +18,7 @@
     let config = await client.memory.readGuildInfo(message.guild.id);
     const filter = getEmojiByName("ICONS.FILTER")
     let attachmentJump = ""
-    if (config.logging.attachments.saved[message.channel.id + message.id]) { attachmentJump = ` [[View attachments]](${config})` }
+    if (config.logging.attachments.saved[message.channel.id + message.id]) { attachmentJump = ` [[View attachments]](${config.logging.attachments.saved[message.channel.id + message.id]})` }
     let list = {
         messageId: entry(message.id, `\`${message.id}\``),
         sentBy: entry(message.author.id, renderUser(message.author)),
@@ -64,7 +63,7 @@
     }
 
     if (fileNames.files.length > 0) {
-        fileNames.files.forEach(async element => {
+        for (let element of fileNames.files) {
             if(!message) return;
             let url = element.url ? element.url : element.local
             if (url != undefined) {
@@ -173,7 +172,7 @@
                     }
                 }
             }
-        });
+        };
     }
     if(!message) return;
 
diff --git a/src/events/messageDelete.ts b/src/events/messageDelete.ts
index 2263d51..3c23739 100644
--- a/src/events/messageDelete.ts
+++ b/src/events/messageDelete.ts
@@ -14,6 +14,7 @@
         let content = message.cleanContent
         content.replace(`\``, `\\\``)
         if (content.length > 256) content = content.substring(0, 253) + '...'
+        let attachments = message.attachments.size + (message.content.match(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi) ?? []).length
         let attachmentJump = ""
         let config = (await client.database.guilds.read(message.guild.id)).logging.attachments.saved[message.channel.id + message.id];
         if (config) { attachmentJump = ` [[View attachments]](${config})` }
@@ -35,7 +36,7 @@
                 sentIn: entry(message.channel.id, renderChannel(message.channel)),
                 deleted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                 mentions: message.mentions.users.size,
-                attachments: entry(message.attachments.size, message.attachments.size + attachmentJump),
+                attachments: entry(attachments, attachments + attachmentJump),
                 repliedTo: entry(
                     message.reference.messageId || null,
                     message.reference.messageId ? `[[Jump to message]](https://discord.com/channels/${message.guild.id}/${message.channel.id}/${message.reference.messageId})` : "None"