console.time('StartUp');
const express = require('express');
var app = express();
const path = require('path');
const http = require('http');
const {Server} = require('socket.io');
const mongoose = require('mongoose');
const port = process.env.PORT || 5000;
const {Client, GatewayIntentBits,Partials, ActivityType} = require('./lib.js');
const Spawner = require('child_process');
const GuildM = require('./models/guilds')

app.use(express.static(path.join(__dirname, "public")));
app.set("view engine", "ejs");
app.use(require('cors')())
app.use(express.json());
app.use(express.urlencoded({extended:true}));

const mongoDB = process.env.mongoDB;
  
const server = http.createServer(app);
const io = new Server(server);

var Childs = [];


const bot = new Client({ intents: [
    GatewayIntentBits.Guilds,  
    GatewayIntentBits.GuildMembers,
    GatewayIntentBits.GuildBans,
    GatewayIntentBits.GuildEmojisAndStickers,
    GatewayIntentBits.GuildIntegrations ,
    GatewayIntentBits.GuildWebhooks ,
    GatewayIntentBits.GuildInvites ,
    GatewayIntentBits.GuildVoiceStates,
    GatewayIntentBits.GuildPresences,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.GuildMessageReactions,
    GatewayIntentBits.GuildMessageTyping,
    GatewayIntentBits.DirectMessages,
    GatewayIntentBits.DirectMessageReactions,
    GatewayIntentBits.DirectMessageTyping,
    GatewayIntentBits.MessageContent,
    GatewayIntentBits.GuildScheduledEvents,
    GatewayIntentBits.AutoModerationConfiguration,
    GatewayIntentBits.AutoModerationExecution],
    partials: [
        Partials.Reaction,
        Partials.Message 
      ]
});
(function login()
{
    bot.login(process.env.discord_token).catch(()=>{login()});
})()

function connectToDB()
{
    mongoose.connect(mongoDB)
        .catch(err=>
            {
                console.log('Server: Error: There was an Error with the connection to the database, attempting to restart it.', err)
                connectToDB();
            });
}

bot.on('ready', () => 
{
    mongoose.Promise = global.Promise;
    connectToDB();
    console.log(`--------------------------\n    ${bot.user.tag.split('#')[0]}   \n          Ready           \n       on `+bot.guilds.cache.size+" guilds         \n    serving "+bot.users.cache.size+" users        \n--------------------------")
    bot.user.setPresence({
        activities: [{ name: `!help`, type: ActivityType.Listening}],
        status: 'online',
    });
    server.listen(port, () => 
    {
        app.use('/', require('./routes/routes')(io, bot));
        console.log(`Http-Server UP`);
    });

    console.timeEnd('StartUp');
    bot.guilds.cache.forEach(guild=>
        {
            GuildM.find({gID:guild.id})
            .then(
                (guild_,err)=>
                {
                    if(err || guild_.length==0)
                    {
                        var nGuild = GuildM();
                        nGuild.name = guild.name;
                        nGuild.memberCount = guild.members.cache.size;
                        nGuild.gID = guild.id;
                        nGuild.strikes = false;
                        nGuild.music = false;
                        nGuild.save(err=>
                            {
                                if(err) console.log('Server: Adding non existing guilds to the DB. Error ocurred:', err)
                            });
                    }
                }
            )
        })
    music();
  setInterval(() => 
  {
    music();
  }, 60000);
    setInterval(() => {
        moveAFKs();
    }, 5*60*1000);
});
bot.on('guildCreate', guild=> 
{
    var guildModel = new GuildM();
    guildModel.name = guild.name;
    guildModel.memberCount = guild.members.cache.size;
    guildModel.gID = guild.id;
    guildModel.strikes = false;
    guildModel.music = false;
    guildModel.save()
});
bot.on('guildDelete', guild => 
{
    GuildM.find({gID:guild.id}).then(guild=>
        {
            if(guild.length==0) return sendMessage(false, 'ID not on the list.')
            GuildM.findOneAndRemove(guild.id, (err)=>
            {
                if(err) console.log('Server: Deleting guild from DB: There was an error:', err)
            })
        })
});
async function music()
{
    //console.log('Music: Looking for Servers.')
    const ServersWithMusicOn = await serversWithMusicOn(bot.guilds.cache);
    if(!ServersWithMusicOn) return 
    for(var server of ServersWithMusicOn)
    {
        if(!Childs[server.name])
        {
            console.log('Index: Starting Music Worker:', server.name,`(${server.gID})`)
            Childs[server.name] = Spawner.fork('./musicWorker.js',[server.gID, server.name]);
        }
        else
        {       //Health check
           (function (server)
           {
                Childs[server.name].on('exit', ()=>
                {
                    console.log('Child DIED, spawning another.')
                    Childs[server.name] = Spawner.fork('./musicWorker.js',[server.gID, server.name]);
                })
            })(server);
        }

    } 
}

function moveAFKs(){
    //Gets the members inside the AFK channel
    let auxmembers = bot.channels.cache.get("335494006890823680").members
    //console.log("MoveAFK: Member list with "+ auxmembers.size+" members.")
    //Sorts through them looking for those who have the SS - Secret Services Role
    if(auxmembers.size >0)
    {
        //console.log("hosting:");
    }
    for(var [key, values] of auxmembers){
       //console.log(values.id);;
        if(values.roles.cache.has('693413934715240498')){ 
            //Upon fiding someoe that has said role.           
            //Moves it to the correct Channel.
            values.voice.setChannel('839266096401874974')
                    .then(() => console.log(`MoveAFK: Moved ${values.displayName}.`))
                    .catch(console.error);
        }
    }
}

async function serversWithMusicOn()
{
    return await GuildM.find({music:true}).then(g=>{return g})
}