// coordinator
// http
const http = require('http')
// filesystem
const fs = require('fs')
// server config
const config = require('./config.json')
// node date time
const node_time = require('node-datetime')

const mongodb_client = require('./mongodb_client.js')

const crypto = require('crypto')

var querystring = require('querystring')

const http_client = require('../lib/http_client.js')
const logger = require('../lib/logger')

// logger
const logger_init = new logger('./logs/init.log')
const logger_runtime = new logger('./logs/runtime.log')

// response function
async function create_response(request, callback) {
    var mongo_client = new mongodb_client(config.mongodb_url)
    var database = await mongo_client.connect_database(config.database_name)

    var response = ''
    try {
        if (request.verb == 'GET_TITLES') {
            var title = database.collection('title')
            response = await title.find().skip(request.start).limit(request.count).toArray()
            callback(response)

        } else if (request.verb == 'PLAN_SESSION') {
            var session_sheduled = database.collection('session_sheduled')
            var sessions = await session_sheduled.find().toArray()
            callback(response)
        } else if (request.verb == 'CREATE_SESSION') {
            
            var session_server = database.collection('session_server')
            var servers = await session_server.find({'title':request.title}).toArray()
            
            if (!servers.length) {
                response = {msg:'SERVERS_NOT_FOUND'}
                callback(response)
                return
            }
            // find free server and create session
            var session_active = database.collection('session_active')

            // find free server
            var free_server
            var servers_length = servers.length
            for (var i = 0; i < servers_length; ++i) {
                var sessions = await session_active.find({'server_id':servers[i].server_id}).toArray()
                if (servers[i].limit > sessions.length) {
                    free_server = servers[i]
                    break
                }
            }
            if (free_server == null) {
                response = {msg:'SESSION_LIMIT_REACHED'}
                callback(response)
                return
            }
            
            var session_id = crypto.randomBytes(16).toString('base64')

            // create session on session server
            new http_client(free_server.ip, free_server.port).post(
                JSON.stringify({verb:'CREATE_SESSION', title:request.title, session_id:session_id}), async function(answer) {

                var json_answer = await JSON.parse(answer)

                if (json_answer.link == null) {
                    response = {msg:'SESSION_SERVER_NOT_WORKING'}
                    callback(response)
                    return
                }

                // generate random code for session access
                var code = Math.floor(1000 + Math.random() * 9000)
                while ((await session_active.find({'code':code}).toArray()).length) {
                    code = Math.floor(1000 + Math.random() * 9000)
                }

                // add session to database
                await session_active.insertOne({
                    server_id:free_server.server_id,
                    session_id:session_id,
                    connection_link:json_answer.link,
                    connection_code:code
                })
                response = {msg:'SESSION_CREATED', link:json_answer.link}
                callback(response)
                return
            },
            function(error) {
                logger_runtime.error(error)
                callback({msg:'SESSION_SERVER_DISABLED'})
                return
            })

        } else if (request.verb == 'CONNECT_SESSION') {
            callback(response)
            return
        } else if (request.verb == 'CLOSE_SESSION') {
            await database.collection('session_active').deleteOne({session_id:request.session_id})
            response = {msg:"SESSION_CLOSED", session_id:request.session_id}
            callback(response)
            return
        } else {
            response = {msg:'UNKNOWN_VERB'}
            callback(response)
            return
        }
    } catch(e) {
        logger_runtime.error(e)
    }
}


// start http server
const server = http.createServer(function(request, response) {
    if (request.method == 'POST') {
        var body = ''
        request.on('data', function(data) {
            body += data
        })
        request.on('end', function() {
            logger_runtime.log('received: ', body)
            response.writeHead(200, {'Content-Type': 'application/json'})
            try {
                create_response(JSON.parse(body), function(message) {
                    response.end(JSON.stringify(message))
                    logger_runtime.log('response:', message)
                })
            }
            catch(e) {
                logger_runtime.error(e)
            }
        })
    }
    else {
        response.writeHead(501, {'Content-Type': 'application/json'})
        response.end(JSON.stringify({msg:'UNKNOWN_METHOD'}))
    }
})

try {
    server.listen(config.port, config.ip)
    logger_init.log(`Listening at http://${config.ip}:${config.port}`)
} catch (e) {
    logger_init.error(e)
}