Source: models/CetusCycle.js

import { fromNow, timeDeltaToString } from 'warframe-worldstate-data/utilities';

import mdConfig from '../supporting/MarkdownSettings.js';

import WorldstateObject from './WorldstateObject.js';

const nightTime = 3000;

const maximums = {
  day: 6000000,
  night: 3000000,
};

/**
 * Represents the current Earth Day/Night Cycle
 * @augments {WorldstateObject}
 */
export default class CetusCycle extends WorldstateObject {
  /**
   * The end of the Ostron bounties timer (marks the end of night)
   * @type {Date}
   * @private
   */
  #bountiesEndDate;
  /**
   * The current cetus cycle, for calculating the other fields
   * @type {object}
   * @private
   */
  #ec;

  /**
   * @param   {Date}              bountiesEndDate The end date for Ostron bounties
   */
  constructor(bountiesEndDate) {
    super({ _id: { $oid: 'cetusCycle0' } });

    this.#bountiesEndDate = bountiesEndDate;
    this.#ec = this.getCurrentCetusCycle();

    /**
     * The date and time at which the event ends
     * @type {Date}
     */
    this.expiry = this.#ec.expiry;

    /**
     * The date and time at which the event started
     * @type {Date}
     */
    this.activation = new Date(this.#ec.start);

    /**
     * Whether it's daytime
     * @type {boolean}
     */
    this.isDay = this.#ec.dayTime;

    /**
     * Current cycle state. One of `day`, `night`
     * @type {string}
     */
    this.state = this.#ec.state;

    /**
     * Time remaining string
     * @type {string}
     */
    this.timeLeft = this.#ec.timeLeft;

    /**
     * Whether this is for Cetus Cycle
     * @type {boolean}
     */
    this.isCetus = true;

    this.id = `cetusCycle${this.expiry.getTime()}`;

    this.shortString = `${this.timeLeft.replace(/\s\d*s/gi, '')} to ${this.isDay ? 'Night' : 'Day'}`;
  }

  /**
   * Get whether or not the event has expired
   * @returns {boolean} whether the event has expired
   */
  getExpired() {
    return fromNow(this.expiry) < 0;
  }

  getCurrentCetusCycle() {
    const now = Date.now();
    const bountiesClone = this.#bountiesEndDate;
    bountiesClone.setSeconds(0);
    let millisLeft = fromNow(bountiesClone);
    const secondsToNightEnd = (millisLeft / 1000).toFixed(0);
    const dayTime = secondsToNightEnd > nightTime;

    const secondsRemainingInCycle = dayTime ? secondsToNightEnd - nightTime : secondsToNightEnd;
    millisLeft = secondsRemainingInCycle * 1000;
    const minutesCoef = 1000 * 60;
    const expiry = new Date(Math.round((now + millisLeft) / minutesCoef) * minutesCoef);
    const state = dayTime ? 'day' : 'night';

    return {
      dayTime,
      timeLeft: timeDeltaToString(millisLeft),
      expiry,
      expiresIn: millisLeft,
      state,
      start: expiry.getTime() - maximums[state],
    };
  }

  /**
   * The event's string representation
   * @returns {string} The string representation of the event
   */
  toString() {
    const lines = [
      `Operator, Cetus is currently in ${this.state}time`,
      `Time remaining until ${this.isDay ? 'night' : 'day'}: ${this.timeLeft}`,
    ];

    return lines.join(mdConfig.lineEnd);
  }
}