import { createServer } from "node:http";
import next from "next";
import { Server } from "socket.io";

const dev = process.env.NODE_ENV !== "production";
const hostname = "localhost";
const port = 3000;
// when using middleware `hostname` and `port` must be provided below
const app = next({ dev, hostname, port });
const handler = app.getRequestHandler();

let active_rooms = {}

function findUserBySocketId(roomId, socketId){
  let ans = null
  active_rooms[roomId].users.forEach((player, index) => {
    if(player.id == socketId){
      ans = index
    }
  })
  return ans
} 

function findUserByBrowserId(roomId, browserId){
  let ans = null
  active_rooms[roomId].users.forEach((player, index) => {
    if(player.browserId == browserId){
      ans = index
    }
  })
  return ans
}

function removeUnusedRoom(roomId){
  let removeRoom = true
  active_rooms[roomId].users.forEach((player) => {
    if(player.connected == true){
      removeRoom = false
    }
  })
  if(removeRoom){
    delete active_rooms[roomId]
  }
}

app.prepare().then(() => {
  const httpServer = createServer(handler);

  const io = new Server(httpServer);

  io.on("connection", (socket) => {
    console.log("User connected " + socket.id)

    socket.on('room_connect', (params) => {

      // IF ROOM DOESN'T EXISTS
      if(!Object.keys(active_rooms).includes(params.id)){
        console.log("First person joined " + params.id + " ! " + params.name + " is owner.")
        active_rooms[params.id] = { gameStarted: false, users: [{id: socket.id, name: params.name, avatar: params.avatar, browserId: params.browserId, connected: true, role: "owner", vote: ""}]}
        socket.emit("room_joined", {"room_users": active_rooms[params.id].users, role: "owner"})
      }

      // IF ROOM EXISTS
      else {
        let userIndexByBrowserId = findUserByBrowserId(params.id, params.browserId)

        // IF USER ALREADY CONNECTED
        if(userIndexByBrowserId != null) {
          active_rooms[params.id].users[userIndexByBrowserId].connected = true
          active_rooms[params.id].users[userIndexByBrowserId].id = socket.id
          socket.emit("room_joined", {"room_users": active_rooms[params.id].users, role: active_rooms[params.id].users[userIndexByBrowserId].role})
          if(active_rooms[params.id].gameStarted){
            socket.emit("start_game",{possibleChoice: active_rooms[params.id].possibleChoice, question: active_rooms[params.id].question, questionNbr: active_rooms[params.id].questionNbr, duration: 15})
          }
        }

        // IF USER DIDN'T CONNECT ONCE
        else {
          socket.to(params.id).emit("new_player",{"id": socket.id, "name": params.name, avatar: params.avatar, browserId: params.browserId, connected: true, role: "player"})
          active_rooms[params.id].users.push({id: socket.id, name: params.name, avatar: params.avatar, browserId: params.browserId, connected: true, role: "player", vote: ""})
          socket.emit("room_joined", {"room_users": active_rooms[params.id].users, role: "player"})
          console.log("New person joined " + params.id + " ! " + params.name + " is player.")
        }
      }
      socket.join(params.id)
    })

    socket.on("start_game", (params) => {
      active_rooms[params.roomId].question = params.question
      active_rooms[params.roomId].questionNbr = 1
      active_rooms[params.roomId].possibleChoice = params.possibleChoice
      active_rooms[params.roomId].duration = params.duration
      active_rooms[params.roomId].gameStarted = true
      socket.to(params.roomId).emit("start_game",{possibleChoice: params.possibleChoice, question: params.question, questionNbr: 1, duration: params.duration})
    })

    socket.on("reset_game", (params) => {
      socket.to(params.roomId).emit("reset_game")
    })

    socket.on("next_question", (params) => {
      active_rooms[params.roomId].question = params.question
      active_rooms[params.roomId].questionNbr += 1
      active_rooms[params.roomId].possibleChoice = params.possibleChoice
      active_rooms[params.roomId].duration = params.duration
      socket.to(params.roomId).emit("next_question",{possibleChoice: params.possibleChoice, question: params.question, duration: params.duration})
    })

    socket.on("question_reply", (params) => {
      socket.to(params.roomId).emit("question_reply", params.data)
    })

    socket.on("player_choice", (params) => {
      console.log(params)
      socket.to(params.roomId).emit("player_choice", {choice: params.choice, player: params.player})
    })

    socket.on("disconnecting", (reason) => {
      for (const room of socket.rooms) {
        if (room !== socket.id) {
          let roomUserIndex = findUserBySocketId(room, socket.id)
          if(roomUserIndex != null){
            active_rooms[room].users[roomUserIndex].connected = false
            socket.to(room).emit("player_disconnected")
            removeUnusedRoom(room)
          }
        }
      }
    })
    // ...
  });

  httpServer
    .once("error", (err) => {
      console.error(err);
      process.exit(1);
    })
    .listen(port, () => {
      console.log(`> Ready on http://${hostname}:${port}`);
    });
});