import { selectorFamily } from 'recoil';
import now from '../atoms/now';
import initTime from '../atoms/initTime';

/**
 * Read-only selector family for subscribing to the _raw time_ at a certain
 * updating interval. The key of the family is the period of the update in
 * milliseconds; for example, `intervalTime(5000)` will update every 5 seconds.
 *
 * Note that this selector will generally not be used directly. It returns
 * a numerical UNIX timestamp that updates on the appropriate interval; if you
 * want a JavaScript `Date` object (which you generally do) you should the
 * `interval` selector which wraps this selector.
 *
 * If no period is provided or if the period is invalid (less than one, falsey,
 * etc.), then the period is automatically set to `1`, which means that the
 * interval will update _each time the `now` atom updates_. In general you
 * should _always_ provide an explicit interval value.
 *
 * For those interested in the nitty gritty workings of the `time` atoms, this
 * selector family is an important piece of the puzzle, because the fact that
 * it returns a primitive value allows Recoil to memoize it across
 * recomputations. That memoization means that anything downstream of this
 * selector family (either other Recoil selectors or components directly) will
 * _only_ recompute or rerender once each period even though this selector
 * recomputes each time the `now` atom updates.
 */
const intervalTime = selectorFamily({
  key: 'test.selectors.intervalTime',
  get: period => ({
    get
  }) => {
    const time = get(now);
    const initTimeValue = get(initTime) || time;
    if (!time) return undefined;
    const safePeriod = Math.max(1, period || 0);
    const elapsedPeriods = Math.floor((time - initTimeValue) / safePeriod);
    return initTimeValue.getTime() + elapsedPeriods * safePeriod;
  }
});
export default intervalTime;