const ROLE_EYE = 'Eye';
const ROLE_RUNNER = 'Runner';

class Room {
  constructor(code) {
    this.code = code;
    this.state = 'lobby'; // lobby | starting | playing
    this.players = [];
    this.createdAt = Date.now();
    this.nextPlayerId = 1;
  }

  addPlayer(ws, name, isHost) {
    const id = this.nextPlayerId++;
    const role = this.hasEye() ? ROLE_RUNNER : ROLE_EYE;

    this.players.push({
      id,
      ws,
      name,
      role,
      isReady: false,
      isHost
    });

    return id;
  }

  removePlayer(playerId) {
    const idx = this.players.findIndex(p => p.id === playerId);
    if (idx < 0) return;

    const removed = this.players[idx];
    this.players.splice(idx, 1);

    // If host left, promote next player
    if (removed.isHost && this.players.length > 0) {
      this.players[0].isHost = true;
    }

    // If Eye left, reassign
    if (removed.role === ROLE_EYE && this.players.length > 0) {
      this.players[0].role = ROLE_EYE;
    }
  }

  getPlayer(playerId) {
    return this.players.find(p => p.id === playerId);
  }

  hasEye() {
    return this.players.some(p => p.role === ROLE_EYE);
  }

  setReady(playerId, ready) {
    const p = this.getPlayer(playerId);
    if (p) p.isReady = ready;
  }

  setName(playerId, name) {
    const p = this.getPlayer(playerId);
    if (p) p.name = name.substring(0, 20);
  }

  swapRole(playerId) {
    const requester = this.getPlayer(playerId);
    if (!requester) return;

    if (requester.role === ROLE_RUNNER) {
      // Take Eye from current Eye
      const currentEye = this.players.find(p => p.role === ROLE_EYE);
      if (currentEye) {
        currentEye.role = ROLE_RUNNER;
        currentEye.isReady = false;
      }
      requester.role = ROLE_EYE;
      requester.isReady = false;
    } else if (this.players.length > 1) {
      // Give Eye to first Runner
      requester.role = ROLE_RUNNER;
      requester.isReady = false;
      const nextRunner = this.players.find(p => p.id !== playerId && p.role === ROLE_RUNNER);
      if (nextRunner) {
        nextRunner.role = ROLE_EYE;
        nextRunner.isReady = false;
      }
    }
  }

  canStart() {
    if (this.players.length < 2) return false;
    if (!this.hasEye()) return false;
    return this.players.every(p => p.isReady);
  }

  resetReady() {
    this.players.forEach(p => { p.isReady = false; });
  }

  isEmpty() {
    return this.players.length === 0;
  }

  getPlayerCount() {
    return this.players.length;
  }

  getHostId() {
    const host = this.players.find(p => p.isHost);
    return host ? host.id : null;
  }

  getPlayersData() {
    return this.players.map(p => ({
      id: p.id,
      name: p.name,
      role: p.role,
      isReady: p.isReady,
      isHost: p.isHost
    }));
  }

  getPlayerWs(playerId) {
    const p = this.getPlayer(playerId);
    return p ? p.ws : null;
  }
}

class RoomManager {
  constructor() {
    this.rooms = new Map();
  }

  createRoom() {
    let code;
    do {
      code = this.generateCode();
    } while (this.rooms.has(code));

    const room = new Room(code);
    this.rooms.set(code, room);
    return room;
  }

  getRoom(code) {
    return this.rooms.get(code) || null;
  }

  deleteRoom(code) {
    this.rooms.delete(code);
  }

  getRoomCount() {
    return this.rooms.size;
  }

  getStats() {
    const rooms = [];
    this.rooms.forEach((room, code) => {
      rooms.push({
        code,
        state: room.state,
        players: room.getPlayerCount(),
        createdAt: room.createdAt
      });
    });
    return { totalRooms: this.rooms.size, rooms };
  }

  cleanupStale(maxAge) {
    const now = Date.now();
    const toDelete = [];
    this.rooms.forEach((room, code) => {
      if (now - room.createdAt > maxAge && room.isEmpty()) {
        toDelete.push(code);
      }
    });
    toDelete.forEach(code => this.rooms.delete(code));
  }

  generateCode() {
    const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
    let code = '';
    for (let i = 0; i < 6; i++) {
      code += chars[Math.floor(Math.random() * chars.length)];
    }
    return code;
  }
}

module.exports = { Room, RoomManager };
