import User from "./User";
import { getTimeline, getTimelineNames } from "./timeline";
import { getCurrentTime } from "./util";

export interface RoomOptions {
  seekTime: number;
  timelineName: string;
}

export interface TickerMessage {
  user: User;
  message: string;
}

// FIXME: dedupe with frontend
export interface SerializedRoom {
  id: number;
  userCount: number;
  isLeader: boolean;
  running: boolean;
  startTime?: number;
  seekTime: number;
  timelineName: string;
  readyToParticipate: boolean;
  speedFactor: number;
  ticker: string[];
  users?: { id: string; readyToParticipate: boolean }[];
}

export default class Room {
  id = 0;
  users: User[] = [];
  leader: User | null = null;

  ticker: TickerMessage[] = [];

  running = false;
  startTime: number | undefined = undefined;

  seekTime = 0;
  timelineName = "Centurion";

  // For debugging purposes
  speedFactor = 1;

  constructor(name: number) {
    this.id = name;
  }

  serialize(user?: User) {
    const obj: SerializedRoom = {
      id: this.id,
      userCount: this.users.length,
      isLeader: this.leader === user,
      running: this.running,
      startTime: this.startTime,
      timelineName: this.timelineName,
      seekTime: this.seekTime,
      readyToParticipate: this.getLeader()?.readyToParticipate || false,
      speedFactor: this.speedFactor,
      ticker: this.ticker.map((i) => i.message),
    };

    if (typeof user === "undefined" || this.leader === user) {
      obj["users"] = this.users.map((u) => u.serialize());
    }

    return obj;
  }

  serializeTimeline() {
    return getTimeline(this.timelineName);
  }

  sync() {
    this.users.forEach((u) => u.sync());
  }

  async join(user: User) {
    this.users.push(user);
    await user.setRoom(this);

    if (!this.hasLeader()) {
      this.setLeader(user);
    }

    this.sync();
  }

  async leave(user: User) {
    this.removeTickerMessageForUser(user);
    this.users.splice(this.users.indexOf(user), 1);
    await user.setRoom(null);

    if (this.leader == user) {
      this.setRandomLeader();
    }

    this.sync();
  }

  setOptions(options: { seekTime: number; timelineName: string }) {
    this.seekTime = Math.max(0, Math.min(options.seekTime, 250 * 60 * 1000));
    if (getTimelineNames().indexOf(options.timelineName) >= 0) {
      this.timelineName = options.timelineName;
    }
    this.sync();
  }

  start() {
    this.running = true;
    this.startTime = getCurrentTime() - this.seekTime;
    this.sync();
  }

  /**
   *
   * @returns {boolean}
   */
  hasUsers() {
    return this.users.length !== 0;
  }

  setRandomLeader() {
    if (this.hasUsers()) {
      this.leader = this.users[0];
    }
  }

  hasLeader(): boolean {
    return this.leader != null;
  }

  setLeader(user: User) {
    this.leader = user;
  }

  getLeader(): User | null {
    return this.leader;
  }

  submitTickerMessage(user: User, message: string) {
    message = message.replace("\n", "");

    this.removeTickerMessageForUser(user);

    this.ticker.push({
      user: user,
      message: message,
    });

    this.sync();
  }

  removeTickerMessageForUser(user: User) {
    let existing = -1;
    for (let i = 0; i < this.ticker.length; i++) {
      if (this.ticker[i].user === user) {
        existing = i;
        break;
      }
    }
    if (existing >= 0) {
      this.ticker.splice(existing, 1);
    }
  }
}
