import express from "express";
import { Server } from "socket.io";
import path from "path";

import Service from "./Service";
import { RoomOptions } from "./Room";

// process.on('SIGINT', () => process.exit());
// process.on('SIGTERM', () => process.exit());

const HOST = "0.0.0.0";
const PORT = 3001;

const app = express();
const httpServer = app.listen(PORT, HOST, () =>
  console.log(`Centurion listening on port ${PORT}!`)
);
app.use(express.static(path.join(__dirname, "../public")));

const io = new Server(httpServer);

const service = new Service();

app.get("/state", (req, res) => {
  return res.json(service.rooms.map((r) => r.serialize()));
});

io.on("connection", (socket) => {
  socket.on("disconnect", async () => {
    await service.onSocketDisconnect(socket);
  });

  socket.on("ping", () => {
    socket.emit("pong");
  });

  socket.on("time_sync", (requestId: number, clientTime: number) => {
    if (!Number.isSafeInteger(requestId)) return;
    if (!Number.isSafeInteger(clientTime)) return;

    service.onTimeSync(socket, requestId, clientTime);
  });

  socket.on("room_options", (options: RoomOptions) => {
    if (!options) return;
    if (!options.timelineName || typeof options.timelineName !== "string")
      return;
    if (!Number.isSafeInteger(options.seekTime)) return;

    service.onSetRoomOptions(socket, options);
  });

  socket.on("request_start", () => {
    service.onRequestStart(socket);
  });

  socket.on(
    "request_join",
    async (roomId: number, callback: (err?: string, res?: boolean) => void) => {
      if (!Number.isSafeInteger(roomId)) {
        return callback("Invalid roomId.");
      }

      if (!service.hasRoomId(roomId)) {
        // cannot join a room that does not exist.
        return callback(undefined, false);
      }

      try {
        const didJoinRoom = await service.onRequestJoin(socket, roomId);
        callback(undefined, didJoinRoom);
      } catch (e) {
        callback(e instanceof Error ? e.message : "Unknown error.");
      }
    }
  );

  socket.on("request_set_ready", () => {
    service.onRequestSetReady(socket);
  });

  socket.on("request_join_random", async () => {
    await service.onRequestJoinRandom(socket);
  });

  socket.on(
    "submit_ticker_message",
    (message?: unknown, callback?: (res?: null, err?: string) => void) => {
      if (typeof message !== "string") {
        return callback && callback(null, "Invalid message.");
      }

      if (message.length > 192) {
        // perfect voor het Wilhelmus
        return callback && callback(null, "Message too long.");
      }

      try {
        service.submitTickerMessage(socket, message);
        return callback && callback();
      } catch (e) {
        console.error(e);
        return (
          callback &&
          callback(null, e instanceof Error ? e.message : "Unknown error")
        );
      }
    }
  );

  service.onSocketConnect(socket);

  // if (name == 'request_join') {
  //     let roomId = params && params['roomId'];
  //     if (!Number.isSafeInteger(roomId)) {
  //         call.error('Invalid room id');
  //         return;
  //     }
  //     if (!service.hasRoomId(roomId)) {
  //         call.respond(false);
  //         return;
  //     }
  //     if (service.onRequestJoin(socket, roomId)) {
  //         call.respond(true);
  //     } else {
  //         call.respond(false);
  //     }
  // }

  /*socket.on('join_room', (roomId, callback) => {
        if (!callback || typeof callback !== 'function') {
            console.error("Join: Callback not a function.");
            return
        }

        if (!roomId) {
            return callback('no_room_id_given');
        }

        if (!Number.isSafeInteger(+roomId)) {
            return callback('room_id_not_integer');
        }

        console.log(`${socketId} wants to join '${roomId}'.`);

        // Leave current room first

        let currentRoom = service.getUserRoom(socketId);
        if (currentRoom) {
            socket.leave(currentRoom.name);
            service.leaveRoom(socketId);
        }

        const room = service.joinRoom(socketId, roomId);

        socket.join(room.name);
        sendRoom(socket, room);
    });

    socket.on('room_info', callback => {
        if (!callback || typeof callback !== 'function') {
            console.error("Room info: Callback not a function.");
            return
        }

        const room = service.getUserRoom(socketId);
        sendRoom(socket, room);
    });

    socket.on('request_start', (time = null) => {
        console.log('request start', socket.rooms);

        const room = service.getUserRoom(socketId);
        if (!room.isLeader(socketId)) {
            console.warn("Non leader tried to start.");
            return;
        }

        room.run(io);
        sendRoom(io.to(room.name.toString()), room);

        if (typeof time === 'number' && time) {
            console.log("Starting at", time);
            room.seek(io, time);
        }
    });*/
});
