"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.msToTimeAgo = exports.toFriendlyDate = exports.toDateString = exports.toTimeString = exports.fromSimpleISODateString = exports.toSimpleISODateString = exports.getStartOfDate = exports.toDateCopy = void 0;

//@ts-check

/**
 * Turns a string into a Date if not already a Date object.
 *
 * @param {Date | string | number} date
 * @returns {Date}
 */
const toDate = date => date instanceof Date ? date : new Date(date);
/**
 * @param {number | string} num Number to zero-pad as two-digit string
 * @returns {string}
 */


const pad = num => (num + '').padStart(2, '0');
/**
 * @param {Date | number | null} [date] If falsy will just return today
 * @returns
 */


const toDateCopy = date => {
  if (typeof date === 'number') {
    return new Date(date);
  } else if (date && date.valueOf) {
    return new Date(date.valueOf());
  }

  return new Date();
};
/**
 * @param {Date | number | null} date
 * @returns {Date}
 */


exports.toDateCopy = toDateCopy;

const getStartOfDate = date => {
  let copy = toDateCopy(date);
  copy.setMinutes(0);
  copy.setHours(0);
  copy.setSeconds(0);
  copy.setMilliseconds(0);
  return copy;
};
/**
 * @param {Date | number} date Date object or ms
 * @returns {string} As YYYY-MM-DD
 */


exports.getStartOfDate = getStartOfDate;

const toSimpleISODateString = date => {
  date = toDate(date);
  return "".concat(date.getFullYear(), "-").concat(pad(date.getMonth() + 1), "-").concat(pad(date.getDate()));
};
/**
 * @param {string} dateString Date object or ms
 * @returns {Date} Local date
 */


exports.toSimpleISODateString = toSimpleISODateString;

const fromSimpleISODateString = dateString => {
  const [year, month, date] = dateString.split('-').map(Number);
  return new Date(year, month - 1, date);
};
/**
 * @param {Date | number | string} date
 * @returns {string} Military time
 */


exports.fromSimpleISODateString = fromSimpleISODateString;

const toTimeString = date => {
  const str = toDate(date).toLocaleTimeString(undefined, {
    hour12: false,
    hour: '2-digit',
    minute: '2-digit'
  }); // workaround for browser/node bug

  return str.replace('24:', '00:');
};
/**
 * @param {Date | number | string} date
 * @param {boolean} [includeTime=false] Default is `false`
 * @returns {string} Locale specific date
 */


exports.toTimeString = toTimeString;

const toDateString = (date, includeTime = false) => {
  const asDate = toDate(date);
  let res = asDate.toLocaleDateString(undefined);

  if (includeTime) {
    res += " ".concat(toTimeString(asDate));
  }

  return res;
};
/**
 * @param {Date | string} date
 * @param {{ now?: Date; includeTime?: boolean }} [options] Date to compare
 *   against (mainly for testing)
 * @returns {string}
 */


exports.toDateString = toDateString;

const toFriendlyDate = (date, {
  includeTime = false,
  now = new Date()
} = {}) => {
  date = toDate(date); // we always want to compare calendar dates
  // not actual time passed this is so that it
  // will properly say "yesterday" if the day
  // was different even if it was only a few hours ago.

  const startOfDate = getStartOfDate(date);
  now = getStartOfDate(now);
  const withinSevenDays = Math.abs(startOfDate.valueOf() - now.valueOf()) < 6.048e8;
  const suffix = includeTime ? " @ ".concat(toTimeString(date)) : '';

  if (!withinSevenDays) {
    const isSameYear = date.getFullYear() === now.getFullYear();
    /** @type {Intl.DateTimeFormatOptions} */

    const opts = {
      month: 'long',
      day: 'numeric'
    };

    if (!isSameYear) {
      opts.year = 'numeric';
    }

    return date.toLocaleDateString(undefined, opts) + suffix;
  } // get a day diff


  const dayDiff = Math.floor((startOfDate.valueOf() - now.valueOf()) / 8.64e7);

  if (dayDiff === -1) {
    return 'Yesterday' + suffix;
  }

  if (dayDiff === 0) {
    return 'Today' + suffix;
  }

  if (dayDiff === 1) {
    return 'Tomorrow' + suffix;
  }

  return "".concat(dayDiff < 0 ? 'Last ' : '').concat(date.toLocaleDateString(undefined, {
    weekday: 'long'
  })) + suffix;
};
/**
 * Turns a number of milliseconds into a friendly "time ago" string.
 *
 * 5000 becomes '5s'
 *
 * @param {number} milliseconds Number of milliseconds that have passed
 * @param {boolean} [includeSeconds] Whether to include seconds in output
 * @returns {string}
 */


exports.toFriendlyDate = toFriendlyDate;

const msToTimeAgo = (milliseconds, includeSeconds = true) => {
  const number = Math.max(milliseconds, 0);
  const seconds = Math.floor(number / 1000 % 60);
  const minutes = Math.floor(number / 60000 % 60);
  const hours = Math.floor(number / 3.6e6);
  let res = '';

  if (hours) {
    res += "".concat(hours, "h ");
  }

  if (minutes) {
    res += "".concat(minutes, "m ");
  }

  if (!includeSeconds && !minutes && !hours) {
    return '0m';
  }

  if (includeSeconds) {
    res += "".concat(seconds, "s");
  }

  return res.trim();
};

exports.msToTimeAgo = msToTimeAgo;