// session server
// 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')
// titles for process creation
const titles = require('./titles.json')

const { spawn } = require('node:child_process')

const child_process = require('child_process')

const port_alloc = require('../lib/port_alloc.js')
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')

var app_port_alloc = new port_alloc(config.session_ports.app_begin, config.session_ports.count)
var http_port_alloc = new port_alloc(config.session_ports.http_begin, config.session_ports.count)

// response function
async function create_response(request, callback) {
    var response = ''
    try {
        if (request.verb == 'CREATE_SESSION') {
            var app_info
            titles.forEach((title) => {
                if (title.title == request.title) {
                    app_info = title
                }
            })
            if (app_info == null) {
                response = {msg:'TITLE_NOT_EXISTS'}
                callback(response)
                return
            }

            var app_port
            var http_port
            try {
                app_port = app_port_alloc.get()
                http_port = http_port_alloc.get()
            } catch(e) {
                logger_runtime.error(e)
                response = {msg:'PORT_BUSY'}
                callback(response)
                return
            }
            
            // start app_proc
            const app_proc = spawn(app_info.path, [].concat(config.app_args_static, 
                [config.app_args_runtime.ip + config.ip, config.app_args_runtime.port + app_port.toString()]), {
                    detached: true
                })
            app_proc.on('error', function(err) {
                logger_runtime.error(err)
                response = {msg:'APP_PROC_ERROR'}
                callback(response)
                return
            })
            app_proc.on('close', (code) => {
                app_port_alloc.free(app_port)
            })

            // start webrtc server
            const webrtc_proc = child_process.fork(config.webrtc_args_static.cirrus_path, [http_port.toString(), app_port.toString()], {
                    detached: true
                })
            webrtc_proc.on('error', function(err) {
                logger_runtime.error(err)
                response = {msg:'WEBRTC_PROC_ERROR'}
                callback(response)
                return
            })
            webrtc_proc.on('close', (code) => {
                http_port_alloc.free(http_port)
                // if webrtc server closed, kill app proc and send session end message to server
                if (process.platform === 'win32') {
                    spawn('taskkill', ['/pid', app_proc.pid, '/f', '/t'])
                }
                else {
                    app_proc.kill('SIGINT')
                }
                new http_client(config.coordinator.ip, config.coordinator.port).post(
                    JSON.stringify({verb:'CLOSE_SESSION', session_id:request.session_id}), function(answer) {
                        
                    },
                    function(error) {

                    })
                
            })

            response = {msg:'SESSION_CREATED', link:`http://${config.ip+':'+http_port}`}
            callback(response)
            return
        } else if(request.verb == 'CONNECT_SESSION') {
            response = ''
            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)
}