/**
 * Value Object: TimeWindow
 * Encapsulates the concept of a time window used for presence detection.
 * The default window is 180 seconds (3 minutes), meaning a user is considered
 * "online" if their last heartbeat was within this window.
 */
export class TimeWindow {
  /** Default presence detection window: 180 seconds (3 minutes) */
  static readonly DEFAULT_SECONDS = 180;

  /** Minimum allowed window: 30 seconds */
  static readonly MIN_SECONDS = 30;

  /** Maximum allowed window: 600 seconds (10 minutes) */
  static readonly MAX_SECONDS = 600;

  private constructor(private readonly seconds: number) {}

  static create(seconds: number = TimeWindow.DEFAULT_SECONDS): TimeWindow {
    if (seconds < TimeWindow.MIN_SECONDS) {
      throw new Error(`Time window must be at least ${TimeWindow.MIN_SECONDS} seconds, got ${seconds}`);
    }
    if (seconds > TimeWindow.MAX_SECONDS) {
      throw new Error(`Time window must be at most ${TimeWindow.MAX_SECONDS} seconds, got ${seconds}`);
    }
    if (!Number.isInteger(seconds)) {
      throw new Error('Time window must be an integer number of seconds');
    }
    return new TimeWindow(seconds);
  }

  /** Create the default 180-second window */
  static default(): TimeWindow {
    return new TimeWindow(TimeWindow.DEFAULT_SECONDS);
  }

  /** Get the window duration in seconds */
  toSeconds(): number {
    return this.seconds;
  }

  /** Get the window duration in milliseconds */
  toMilliseconds(): number {
    return this.seconds * 1000;
  }

  /** Calculate the threshold timestamp (now - window) as Unix epoch seconds */
  getThresholdEpoch(): number {
    return Math.floor(Date.now() / 1000) - this.seconds;
  }

  /** Calculate the threshold timestamp as a Date */
  getThresholdDate(): Date {
    return new Date(Date.now() - this.toMilliseconds());
  }

  equals(other: TimeWindow): boolean {
    return this.seconds === other.seconds;
  }

  toString(): string {
    return `${this.seconds}s`;
  }
}
