const path = require('path');
const find = require('findit');
const {Client,ClientOptions,GatewayIntentBits,Message, Partials, ActivityType,EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle} = require('discord.js')
const roleRulesM = require('./models/autoRoleRule');
const feedM = require('./models/feeds');
const xmlparser = require('xml-js')
module.exports.GatewayIntentBits = GatewayIntentBits;
module.exports.Partials = Partials;
module.exports.ActivityType = ActivityType;
module.exports.EmbedBuilder = EmbedBuilder;
module.exports.ActionRowBuilder = ActionRowBuilder;
module.exports.ButtonBuilder = ButtonBuilder;
module.exports.ButtonStyle = ButtonStyle;
module.exports.Message = Message;

//@ts-check
class CommandOptions 
{
    /**
     * 
     * @param {String} name 
     * @param {String[]} aliases 
     * @param {String} description 
     * @param {Boolean} needsAdmin 
     * @param {Boolean} hidden 
     */
    constructor (name, aliases, description, needsAdmin, hidden)
    {
        this.name = name;
        this.aliases = aliases;
        this.description = description;
        this.needsAdmin = needsAdmin;
        this.hidden = hidden;
    }
}
class command 
{
    /**
     * @param {_Client} client extends discord.js.Client
     * @param {CommandOptions} options extends Lib.Options
     */
    constructor(client, options)
    {
        this.name = options.name;
        this.aliases =  options.aliases;
        this.description = options.description;
        this.needsAdmin =options.needsAdmin;
        this.hidden = options.hidden;
        this.client = client;
    }
}module.exports.Command = command;

// const {func}=require('lib.d.ts');
// func('string');

class _Client extends Client
{
    /**
     * 
     * @param {ClientOptions} options 
     */
    commands = new Map();
    constructor(options)
    {
        super(options)
        let finder = find(path.resolve('commands'));
        finder.on('file', file=>
        {
            let command = require(file);
            if(typeof command === 'function')
            {
                let c = new command(this);
                this.commands.set(c.name,{
                    needsAdmin: c.needsAdmin?c.needsAdmin:false,
                    command: command,
                });
                if(c.aliases)
                {
                    for(var i =0; i<c.aliases.length+1; i++)
                    {
                        this.commands.set(c.aliases[i],{
                            needsAdmin: c.needsAdmin,
                            command: command,
                        });
                    }
                }
            }
        })
        
        finder.on('end', ()=>
        {
            this.enableCommands();
        })
        this.RoleSetter();
        this.rustCommits = new rustCommits(this);
        this.freegames = new FreeGames(this);
        this.strikes = new Strikes(this);
        this.on('disconnect', (event) => {
            // Log a message to the console
            console.log(`Client disconnected: ${event.reason}`);
        });
        
        // Register an event listener for the 'reconnecting' event
        this.on('reconnecting', () => {
            // Log a message to the console
            console.log('Client is reconnecting...');
        });
        this.YTFeed();
        setInterval(() => {
            this.YTFeed()
        }, 60*60*1000);
    }
    /**
     * Register a group of commands under the folder commands
     * @param {String} name - Name of the group.
     * @param {String} folderName - Name of the folder.
     */
    async enableCommands()
    {
        //use needs admin here!!!!
        this.on("messageCreate", message=>
        {
            if(message.content.startsWith('!'))
            {
                let commandName=message.content.split('!')[1].split(' ')[0];
                let args = message.content.split(' ');
                args.splice(0,1);
                args = args.filter(n=>n);
                if(this.commands.get(commandName))
                {
                    let needsAdmin = this.commands.get(commandName).needsAdmin;
                    let isAdmin = this.guilds.cache.get(message.guild.id).members.cache.get(message.author.id).permissions.has('ADMINISTRATOR');
                    let command = this.commands.get(commandName).command
                    if((needsAdmin && isAdmin) || !needsAdmin) return   new command(this).run(message, args);
                }
                new ErrorMessage(this).send(ErrorType.NotOnTheList,message)
            }
        })
    }
    /**
     * 
     * @param {String} name - Command Name
     * @returns {command}
     */
    async RoleSetter ()
    {
        this.on('messageReactionAdd', (reaction, user)=>
            {
                (async ()=>
                {
                    const rule = await roleRulesM.findOne({mID:reaction.message.id,roleEmoji:reaction._emoji.id}).then(rule =>{return rule}).catch(err=>{return null})
                    if(rule)
                    {
                        console.log(`RoleAssignment: Guild:${this.guilds.cache.get(rule.gID)} Role ${rule.roleName} given to ${user.username}`)
                        this.channels.cache.get(reaction.message.channelId).members.get(user.id).roles.add(rule.roleID)
                    }
                })()
            })
            this.on('messageReactionRemove', (reaction, user)=>
            {
                (async ()=>
                {
                    const rule = await roleRulesM.findOne({mID:reaction.message.id,roleEmoji:reaction._emoji.id}).then(rule =>{return rule}).catch(err=>{return null})
                    if(rule)
                    {
                        console.log(`RoleAssignment: Guild:${this.guilds.cache.get(rule.gID)}: Removing, ${user.username}'s ${rule.roleName} role. `)
                        this.channels.cache.get(reaction.message.channelId).members.get(user.id).roles.remove(rule.roleID)
                    }
                })()
            })
    }
    async YTFeed()
    {
        //TODO: Allow multiple feeds per channel 
        //Rust: FacePunch and Shadowfrax
        //!Needs some other element for comparison other than published date

        const feeds = await feedM.find().then(feeds=>{return feeds})
        if(feeds.length<1) return 
        for(var feed of feeds)
        {
            (async (feed)=>{
                var res = await fetch(`https://www.youtube.com/feeds/videos.xml?channel_id=${feed.YTChannelId}`)
                                .then(handleResponse)
                                .then(handleData)
                                .catch(handleError);
                                function handleResponse(response) 
                                {
                                return response.text()
                                }
                                function handleError(error) 
                                {
                                return error;
                                }
                                function handleData(data) 
                                {
                                    data = xmlparser.xml2json(data,
                                                    {
                                                        compact: true,
                                                        space: 4
                                                    });
                                    data = JSON.parse(data);
                                    return {
                                                link:data.feed.entry[0].link._attributes.href,
                                                published:data.feed.entry[0].published._text,
                                                link:data.feed.entry[0].link._attributes.href,
                                                image:data.feed.entry[0].link._attributes.href.split('=')[1],
                                                title:data.feed.entry[0].title._text,
                                                author:
                                                {
                                                    name:data.feed.entry[0].author.name._text,
                                                    url:data.feed.entry[0].author.uri._text
                                                }        
                                            }
                                } 
                if(!res) return false;
                const channel = this.channels.cache.get(feed.ChannelId);
                if(!channel) return false;
                const lastSentMessage = await channel.messages.fetch().then(res=>
                    {
                        for(var item of res)
                        {
                            if(item[1].embeds)
                            {
                                if(item[1].embeds[0])
                                {
                                    var fields = item[1].embeds[0].fields.filter(x=>x.name === 'PublishedTimeStamp');
                                    var isFeed = fields.length>0;
                                    if(isFeed) return fields[0].value
                                }
                            }
                        }
                    })
                if(!lastSentMessage) sendMessage(res, feed, channel)
                else if(lastSentMessage != res.published) sendMessage(res, feed, channel);
            })(feed);
        }
        function sendMessage(res, feed, channel)
        {
            const embed = new EmbedBuilder()
            embed.setFooter({text:'Rem-chan on ', iconURL:"https://i.imgur.com/g6FSNhL.png"})
            embed.setAuthor({name:"Rem-chan", iconURL:"https://i.imgur.com/g6FSNhL.png",url:'https://rem.wordfights.com/addtodiscord'}); 
            embed.setColor(0x110809);
            embed.setTimestamp();
            embed.setURL(res.author.url)
            embed.setTitle(res.author.name);
            embed.setImage(`https://i3.ytimg.com/vi/${res.image}/maxresdefault.jpg`)
            embed.setDescription(feed.CostumMessage);
            embed.addFields({name:'PublishedTimeStamp', value:res.published},
                            {name:'Link:', value:res.link});
            channel.send({embeds:[embed]});
        }
    }

}module.exports.Client = _Client;
const ErrorType = 
{
    Permissions: "Permissions",
    Arguments: "Arguments",
    NoArguments: "No Arguments Given",
    NotOnTheList: "Unknown Command",
    OldMessages: "Can't delete this messages."
}
module.exports.ErrorType = ErrorType;

class Channel 
{
    /**
     * 
     * @param {String} channelID
     */
    constructor(channelID)
    {
        this.channel = channelID;
    }

}

module.exports.Channel = Channel;
/**
 * 
 * @param {Number} length 
 * @returns {String}
 */
function  Random(length) 
{
    length?length:length=5;
    var result           = '';
    var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var charactersLength = characters.length;
    for ( var i = 0; i < length; i++ ) {
        result += characters.charAt(Math.floor(Math.random() * charactersLength));
    }
    return result;
}module.exports.Random = Random;

class ErrorMessage 
{
    /**
     * @param {_Client} client 
     */
    constructor(client)
    {
        this.client = client;
    }
    /**
     * 
     * @param {ErrorType} errorType 
     * @param {Message} message 
     * @param {[String]} extraMessages 
     */
   
    async send(errorType,message, extraMessages)
    {
        if (!message.channel.id) return;
        const embed = new EmbedBuilder()
        .setColor(0x4d0000)
        .setAuthor({name:"Rem-chan", iconURL:"https://i.imgur.com/g6FSNhL.png",url:'https://rem.wordfights.com/addtodiscord'})
        .setTimestamp()
        .setFooter({text:'Rem-chan on ', iconURL:"https://i.imgur.com/g6FSNhL.png"})
        .addFields({name: 'Error:', value: 'something'})
        .addFields({name: 'Try:', value: 'something'});
        
        switch (errorType) {
            case ErrorType.Arguments:
                embed.data.fields[0].value =ErrorType.Arguments;
                embed.data.fields[1].value = 'Verify the arguments provided.'
                break;
            case ErrorType.NoArguments:
                embed.data.fields[0].value =ErrorType.NoArguments;
                embed.data.fields[1].value = 'Provide the required arguments for this command.'
                break;
            case ErrorType.Permissions:
                embed.data.fields[0].value =ErrorType.Permissions;
                embed.data.fields[1].value = 'Ask this servers administrator to use the command.'
                break;
            case ErrorType.NotOnTheList:
                embed.data.fields[0].value =ErrorType.NotOnTheList;
                embed.data.fields[1].value = 'Use !help for the list of available.'
                break;
            case ErrorType.OldMessages:
                embed.data.fields[0].value =ErrorType.OldMessages;
                break;
            default:
                break;
        }
        if(extraMessages)
        {
            for(var i = 0; i<extraMessages.length; i++)
            {
                embed.addFields({name:'Tip:', value:extraMessages[i]});
            }
        }
        const randomID =  Random();
        const row = new ActionRowBuilder()
        .addComponents(
                new ButtonBuilder()
                .setCustomId(randomID)
                .setLabel('Remove this.')
                .setStyle(ButtonStyle.Primary)
                .setEmoji('❌')
        );
        await this.client.channels.cache.get(message.channel.id).send({ephemeral: true, embeds: [embed], components: [row] }); 
    
        const filter = i => i.customId === randomID;

        const collector = message.channel.createMessageComponentCollector({ filter, time: 60000 });

        collector.on('collect', async m => 
        {
            message.delete().then(()=>m.message.delete())
            .catch(()=>m.message.delete());
        });
    }

}module.exports.ErrorMessage = ErrorMessage;

/**
 * AniList Client -> Search Functions
 */
class AnimeInfo
{
    /**
     * 
     * @param {String} title 
     * @param {String} status 
     * @param {String} episodes 
     * @param {String} trailer 
     * @param {String} description 
     * @param {String} coverImage 
     */
    constructor(title, status, episodes, trailer, description, coverImage)
    {
        this.title = title; 
        this.status = status;
        this.episodes=episodes;
        this.trailer = trailer;
        this.description = description;
        this.coverImage = coverImage;
    }
}
class CharInfo
{
    /**
     * 
     * @param {String} name 
     * @param {String} gender 
     * @param {String} image 
     * @param {String} description 
     */
    constructor(name, gender, image, description)
    {
        this.name = name; 
        this.gender = gender;
        this.image=image;
        this.description = description;
    }
}
class MangaInfo
{
    /**
     * 
     * @param {String} title 
     * @param {String} status 
     * @param {String} description 
     * @param {String} coverImage 
     */
    constructor(title, status, description, coverImage)
    {
        this.title = title; 
        this.status = status;
        this.description = description;
        this.coverImage = coverImage;  
    }
}

class aniListCli {
    /**
     * 
     * @param {String} ss - Search Query
     * @returns {AnimeInfo} 
     */
    async searchAnime(ss)
    {
        
        var variables = {
            ss
        };
        var query = `query ($ss: String) {
            Media(search:$ss,type: ANIME) {
              id
              title {
                romaji
                english
                native
              }
              status
              episodes
              trailer {
                site
                id
              }
              description(asHtml:false)
              coverImage {
                large
              }
            }
          }`;
        var url = ``+'https://graphql.anilist.co',
        options = {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json', 
            },
            body: JSON.stringify({
                query,
                variables
            })
        };
        return await fetch(url, options).then(handleResponse)
                   .then(handleData)
                   .catch(handleError);
        function handleResponse(response) 
        {
            return response.json().then(function (json) 
            {
                return response.ok ? json : Promise.reject(json);
            });
        }
        function handleError(error) {
            return error;
        }
        function handleData(data) {
            return {
                title:data.data.Media.title,
                status:data.data.Media.status,
                episodes:data.data.Media.episodes,
                trailer:data.data.Media.trailer,
                description:data.data.Media.description,
                coverImage:data.data.Media.coverImage.large
           }
        }
        
    }
    /**
     * 
     * @param {String} ss - Search Query
     * @returns {CharInfo}
     */
    async searchChar(ss)
    {
        
        var variables = {
            ss
        };
        var query = `query ($ss: String) {
            Character(search: $ss, sort:SEARCH_MATCH) {
              id
              name {
                full
                native
              }
              gender
              image {
                medium
              }
              description(asHtml:false)
            }
          }
          `;
        var url = 'https://graphql.anilist.co',
        options = {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
            },
            body: JSON.stringify({
                query,
                variables
            })
        };
        return await fetch(url, options).then(handleResponse)
                   .then(handleData)
                   .catch(handleError);
        function handleResponse(response) 
        {
            return response.json().then(function (json) 
            {
                return response.ok ? json : Promise.reject(json);
            });
        }
        function handleError(error) {
            return error;
        }
        function handleData(data) {
            return {
                name:data.data.Character.name,
                gender:data.data.Character.gender,
                image:data.data.Character.image.medium,
                description:data.data.Character.description,
           }
        }
        
    }
    /**
     * 
     * @param {String} ss - Search Query
     * @returns {MangaInfo}
     */
    async searchManga(ss)
    {
        
        var variables = {
            ss
        };
        var query = `query ($ss: String) {
            Media(search: $ss, type: MANGA) {
              title {
                romaji
                english
                native
              }
              status
              description(asHtml: false)
              coverImage {
                large
              }
            }
          }
          `;
        var url = 'https://graphql.anilist.co',
        options = {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
            },
            body: JSON.stringify({
                query,
                variables
            })
        };
        return await fetch(url, options).then(handleResponse)
                   .then(handleData)
                   .catch(handleError);
        function handleResponse(response) 
        {
            return response.json().then(function (json) 
            {
                return response.ok ? json : Promise.reject(json);
            });
        }
        function handleError(error) {
            return error;
        }
        function handleData(data) {
            return {
                title:data.data.Media.title,
                status:data.data.Media.status,
                description:data.data.Media.description,
                coverImage:data.data.Media.coverImage.large
           }
        }
        
    }

}module.exports.aniList = aniListCli;

const channelM = require('./models/channels');

class rustCommits
{
    /**
     * 
     * @param {_Client} client 
     */
    constructor(client)
    {
        this.client = client;
        this.update();
        setInterval(() => {
            this.update();
        }, 3*60*1000);
        this.channels;
    }
    async update ()
    {
        const channels = await channelM.find({for:'rust'}).then(channels=>{return channels});
        this.channels = await this.resolveChannels(channels);
        const Res = await fetch("https://commits.facepunch.com/?format=json").then(handleResponse)
                   .then(handleData)
                   .catch(handleError);
        function handleResponse(response) 
        {
            return response.json().then(function (json) 
            {
                return response.ok ? json : Promise.reject(json);
            });
        }
        function handleError(error) {
            return error;
        }
        function handleData(data) {
            data.results.splice(30, 20);
            return data.results.filter(x=>x.repo.search(/rust/i)!=-1)
        }

        for(var j = 0; j<this.channels.length; j++)
        {
            if(!this.channels[j].lastid) this.channels[j].lastid = 0;
            const Pos = Res.map(e => e.id).indexOf(this.channels[j].lastid);
            Res.splice(Pos, Res.length-Pos);
            for(var i = Res.length-1; i>0; i--)
            {
                if(Res[i].id > this.channels[j].lastid)
                {
                    send(
                    {
                        Author:Res[i].user.name,
                        Avatar:Res[i].user.avatar,
                        Time:Res[i].created.split("T")[1]+ " of "+ Res[i].created.split("T")[0],
                        Content:Res[i].message,
                        ID:Res[i].id,
                        Repo:Res[i].repo,
                        Branch:Res[i].branch
                    }, this.channels[j].cID, this.client);
                }
            }
        }
        /**
         * 
         * @param {RustCommit} commit 
         * @param {Channel} channel 
         */
        function send(commit, channel, client)
        {
            client.channels.cache.get(channel).send({embeds:[
                new EmbedBuilder()
                .setColor(0xc23811)
                .setTitle(commit.Time)
                .setURL('https://commits.facepunch.com')
                .setAuthor({name:commit.Author, iconURL:commit.Avatar==''?"https://i.imgur.com/g6FSNhL.png":commit.Avatar,url:`https://commits.facepunch.com/${commit.Author.split(' ').join('')}`})
                .setDescription(commit.Content)
                .addFields(
                    { name:`${commit.Repo}`, value:`[${commit.Repo}/${commit.Branch}](https://commits.facepunch.com/r/${commit.Repo}/${commit.Branch}/ 'Branch Link')`},
                    { name: 'ID', value: commit.ID.toString() },
                    )
                .setTimestamp()
                .setFooter({text:'Rem-chan on ', iconURL:"https://i.imgur.com/g6FSNhL.png"})
            ]});
        }
        
    }
     /**
     * 
     * @param {channelM} channels 
     */
      async resolveChannels(channels)
      {
          for await(var channel of channels )
          {
              if(this.client.channels.cache.get(channel.cID))
              {
                  const Channel = this.client.channels.cache.get(channel.cID)
                  const lastid = await Channel.messages.fetch({limit:1}).then(message=>
                      {
                            if(!message) return 0
                            const [content] = message.values();
                            if(!content||!content.embeds||!content.embeds.length>0) return 0;
                            return parseInt(content.embeds[0].fields[1].value)
                      })
                      channel['lastid'] = lastid;  
              }
          }
          return channels;
      }
}
class RustCommit 
{
    /**
     * 
     * @param {String} Author 
     * @param {String} Avatar - IMAGE URL
     * @param {String} Time 
     * @param {String} Content 
     * @param {Number} ID 
     * @param {String} Repo 
     * @param {String} Branch 
     */
    constructor(Author, Avatar, Time, Content, ID, Repo, Branch)
    {
        this.Author = Author
        this.Avatar = Avatar
        this.Time = Time
        this.Content = Content
        this.ID = ID
        this.Repo = Repo
        this.Branch = Branch
    }
}
class FreeGames
{
    /**
     * 
     * @param {_Client} client 
     */
    constructor(client)
    {
        this.client = client;
        this.update()
        setTimeout(() => {
            this.update();
        }, 3*60*1000);
    }
    async update()
    {
        const channels = await channelM.find({for:'freegames'}).then(channels=>{return channels});
        this.channels = await this.resolveChannels(channels);
        
        const Res = await fetch('https://www.gamerpower.com/api/giveaways').then(handleResponse)
            .then(handleData)
            .catch(handleError);
        function handleResponse(response) 
        {
            return response.json().then(function (json) 
            {
                    return response.ok ? json : Promise.reject(json);
            });
        }
        function handleError(error) {
            return error;
        }
        function handleData(data) {
            data.splice(10, data.length-10);
            return data
        }
        if(!Res.length) return setTimeout(() => 
        {
            update();
        }, 60*1000); 
        for(var j = 0; j<this.channels.length; j++)
        { 
            const Pos = Res.map(e => e.id).indexOf(this.channels[j].lastid);
            Res.splice(Pos, Res.length-Pos)

            for(var i = Res.length-1; i>0; i--)
            {
                if(Res[i].id > this.channels[j].lastid)
                {
                    send(
                    {
                        ID:Res[i].id, //
                        Title:Res[i].title, //
                        Type:Res[i].type, //
                        Thumb:Res[i].thumbnail, //
                        Image:Res[i].image, //
                        Description:Res[i].description, //
                        Instructions:Res[i].instructions,//
                        URL:Res[i].open_giveaway_url,//
                        Platform:Res[i].platforms,//
                        EndDate:Res[i].end_date,
                        
                    }, this.channels[j].cID, this.client);
                }
            }
        }
        /**
         * 
         * @param {FreeGameModel} game 
         * @param {Channel} channel 
         */
        function send(game, channel, client)
        {
            client.channels.cache.get(channel).send({embeds:[
                new EmbedBuilder()
                .setColor(0x2d9134)
                .setURL(game.URL)
                .setTitle(game.Title)
	            .setAuthor({name:"Rem-chan", iconURL:"https://i.imgur.com/g6FSNhL.png",url:'https://rem.wordfights.com/addtodiscord'})
                .setDescription(game.Description)
                .setImage(game.Image)
                .setThumbnail(game.Thumb)
                .addFields(
                    { name: 'Platforms', value: game.Platform},
                    { name: 'Type of offer:', value: game.Type},
                    { name:'Instructions:', value:game.Instructions},
                    { name:`End date:`, value:`${game.EndDate}`},
                    )
                .setTimestamp()
                .setFooter({text:`(${game.ID}) Rem-chan on `, iconURL:"https://i.imgur.com/g6FSNhL.png"})
            ]});
        }
    }
    /**
     * 
     * @param {channelM} channels 
     */
    async resolveChannels(channels)
    {
        for await(var channel of channels )
        {
            if(this.client.channels.cache.get(channel.cID))
            {
                const Channel = this.client.channels.cache.get(channel.cID)
                const lastid = await Channel.messages.fetch({limit:1}).then(message=>
                    {
                        if(!message) return 0
                        const [content] = message.values();
                        if(!content||!content.embeds||!content.embeds.length>0) return 0;
                        return parseInt(content.embeds[0].footer.text.split('(')[1].split(')')[0])
                    })
                    channel.lastid = lastid;  
            }
        }
        return channels;
    }
}

class FreeGameModel
{
    /** 
     * @param {String} ID 
     * @param {String} Title 
     * @param {String} Thumb 
     * @param {String} Type
     * @param {String} Image 
     * @param {String} Description 
     * @param {String} Instructions 
     * @param {String} URL 
     * @param {String} Platform 
     * @param {Date} EndDate 
     */
    constructor(ID, Title, Thumb,Type, Image, Description, Instructions, URL, Platform, EndDate)
    {
        this.ID = ID;
        this.Title = Title;
        this.Type = Type;
        this.Thumb = Thumb;
        this.Image = Image;
        this.Description = Description;
        this.Instructions = Instructions;
        this.URL = URL;
        this.Platform = Platform;
        this.EndDate = EndDate;
    }
}
const strikesM = require('./models/strikes');
const guildsM = require('./models/guilds');
class Strikes
{
    constructor(client)
    {
        this.client = client;
        this.check();
         setInterval(() => {
             this.check();
         }, 5*60*1000);

        //TODO: Handle old strikes
        //* Strikes life time should be difined by guild
        //* A default should be set
        //? 15 days

    }
    async check()
    {
        const Strikes = await strikesM.find().then(s=>{return s});
        //console.log(Strikes);
        const guilds = await guildsM.find({strikes:true}).then(g=>{return g});
        if(!guilds) return console.log('Striker: No Guilds')
        var guildIds = [];
        for(var i = 0; i<guilds.length; i++)
        {
            guildIds.push(guilds[i].gID);
        }
        var filtered = Strikes.filter(
            (e) => {
              return guildIds.indexOf(e.guildID)>=0;
            }            
          )
        guildIds.forEach(guild=>
            {
                filtered.forEach(strike=>
                    {
                        (async (guild, strike)=>
                        {
                            const ammount = await strikesM.find({guildID:guild, strokedID:strike.strokedID}).then(res=>{return res.length}); 
                            if(ammount>2) 
                            {
                                this.handleStroked(strike.strokedID, guild);
                            }
                        })(guild, strike)
                    })
            })
    }
    handleStroked(user, guild)
    {    
        strikesM.deleteMany({ guildID: guild, strokedID: user }, (err, res) => {
            if (!err) return console.log('Strikes Deleted')
          });
        // If the user is found, kick them from the server
        const member = this.client.guilds.cache.get(guild).members.cache.get(user);
        if (!member) return console.log('Strikes: Handle Strikened: Member not valid')
        console.log(member.user.username)
        member.kick('Optional reason that will be displayed in the audit logs')
            .then(() => console.log(`Successfully kicked ${user.user.username}`))
            .catch(err => console.log(`Unable to kick ${user.user.username}: ${err}`));
    } 
}