const https = require('https').createServer;
const WebSocket = require('ws');
const url = require('url');
const fs = require('fs');
const objectsModule = require('./objects');


const options = {
    cert: fs.readFileSync("/home/ubuntu/servers/keys/gta6/cert.pem"),
    key: fs.readFileSync("/home/ubuntu/servers/keys/gta6/privkey.pem")
};

const server = https(options, (req, res)=>{
    res.end("Grand Tabernacle Auto 6")
});

const wss = new WebSocket.Server({
  server
});



const spawnPoints = [{"x":218,"y":193},{"x":601,"y":715},{"x":1264,"y":57},{"x":274,"y":506},{"x":921,"y":854},{"x":1041,"y":442},{"x":638,"y":124},{"x":483,"y":436}]
const connections = new Set();
let playerCount = 0;
let players = []
const MAX_HEALTH = 10;

const NAME_MAXLEN = 25;



function generatePosition() {
  let index = Math.floor(Math.random()*spawnPoints.length);
  return [spawnPoints[index].x, spawnPoints[index].y];
}

function getUsername(req){
  let username = url.parse(req.url, true).query.name;
  if (username === undefined || username == null || username == "null") {
    username = "Soldat Inconnu"
  }
  if (username.length > NAME_MAXLEN) {
    username = username.substring(0, NAME_MAXLEN);
  }
  return username;
}

function createNewPlayer(socket, name) {
  let pos = generatePosition();
  var obj = {
    id: playerCount,
    x: pos[0],
    y: pos[1],
    z: 0,
    dir: 0,
    visibleDir: 0,
    name: name
  }
  players.push(obj);
  playerCount++;

  socket.send(JSON.stringify({
    type: "connect",
    data: {
      playerId: obj.id,
      players: players
    }
  }))

  broadcast(JSON.stringify({
    type: "newplayer",
    data: obj
  }), obj.id);

  socket.id = obj.id;
  connections.add(socket);
}

function kick_player(player_id, socket, reason){
  //send cheating info to all players
  broadcast(JSON.stringify({
    type: "kick",
    data: {
      player_id: player_id,
      reason: reason
    }
  })); 
  deletePlayer(socket); //delete player of players list
  socket.terminate(); //disconnect cheating player
}

function update(message, socket){
  for (var i = players.length - 1; i >= 0; i--) {
    if(message.data.health <= MAX_HEALTH) {
      if (players[i].id == message.data.id) {
        players[i] = message.data;
      }
    }else{
      //cheat detected
      kick_player(message.data.id, socket, "health cheat");
    }
  }
  broadcast(JSON.stringify(message), socket.id);
}

function newBullet(message, socket){
  broadcast(JSON.stringify(message), socket.id);
}

function died(message, socket){
  broadcast(JSON.stringify(message), socket.id);
  for (var i = players.length - 1; i >= 0; i--) {

    if (players[i].id == message.data.id) {
      let pos = generatePosition();
      players[i].x = pos[0];
      players[i].y = pos[1];
      players[i].z = 0;

      broadcast(JSON.stringify({
        type: "update",
        data: players[i]
      }))
    }
  }
}

function deletePlayer(socket){
  for (var i = players.length - 1; i >= 0; i--) {
    broadcast(JSON.stringify({
      type: "removePlayer",
      data: {
        id: socket.id
      }
    }));
    if (players[i].id == socket.id) {
      players.splice(i, 1);
    }
  }
  connections.delete(socket);
}

function recievemessage(msg, socket){
  broadcast(JSON.stringify(msg), socket.id);
}

function broadcast(message, exceptId = -1) {
  connections.forEach((socket) => {
    if (socket.readyState === WebSocket.OPEN && socket.id != exceptId) {
      socket.send(message);
    }
  });
}

wss.on('connection', (socket, req) => {
  //create new player, send informations to new player and broadcast new player for all
  let username = getUsername(req);
  createNewPlayer(socket, username);

  //handle client's messages
  socket.on('message', (message) => {
    try{
      message = JSON.parse(message);
      switch (message.type) {
        case 'ping':
          socket.send("pong");
          break;

        case "update":
          update(message, socket);
          break;

        case "newBullet":
          newBullet(message, socket);
          break;

        case "died":
          died(message, socket);
          break;

        case "message":
          recievemessage(message, socket);
          break;

        default:
          break;
      }
    }catch(e){
      console.log('error');
    }
    
  });

  //handle disconnecting
  socket.on('close', () => {
    deletePlayer(socket);
  });
});

const PORT = 8080;

server.listen(PORT, () => {
  console.log(`WebSocket listening on port ${PORT}.`);
});
