import assert from 'assert';
import StatsLoggerClient from './StatsLoggerClient';

/**
 * @param {array} hrtime process.hrtime() tuple
 * @returns {number} milliseconds
 */
const hrtimeToMilliseconds = (hrtime) => +hrtime[0] * 1000 + +hrtime[1] / 1000000;

/**
 * Logs total request time starting at instantiation and ending when finish() is called.
 * Additional timers can be managed with startTimer('name') and stopTimer('name')
 *
 * Results are stored in `timers` property and submitted to statsd at finish().
 */
export default class RequestTimer {
    /**
     *
     * @param {StatsLoggerClient} statsLoggerClient
     * @param {string} prefix namespace to tack on the front of each timer name
     * @param {string} tags not yet supported by statsd / StatsLoggerClient
     */
    constructor(statsLoggerClient, prefix, tags) {
        assert(statsLoggerClient instanceof StatsLoggerClient, 'provide an instance of StatsLoggerClient');

        this.start = process.hrtime();
        this.timers = [];
        this.inProgressTimers = {};
        this.prefix = prefix;
        this.requestTags = tags;
        this.statsLoggerClient = statsLoggerClient;
    }

    /**
     * @param {string} name
     * @param {number} duration milliseconds
     */
    logSegment(name, duration) {
        this.timers.push([`${this.prefix}.${name}`, duration]);
    }

    /**
     * Starts keeping track of something to time.
     *
     * @param {string} name
     */
    startTimer(name) {
        assert(typeof name === 'string', 'a name for the timer must be provided');

        this.inProgressTimers[name] = process.hrtime();
    }

    /**
     * Stops an in-progress timer and stores it in the list of timers to log when the request is finished.
     *
     * @param {*} name
     */
    stopTimer(name) {
        assert(typeof this.inProgressTimers[name] !== 'undefined', 'provide an existing timer name');

        this.logSegment(name, hrtimeToMilliseconds(process.hrtime(this.inProgressTimers[name])));
        delete this.inProgressTimers[name];
    }

    finish() {
        this.logSegment('total_ms', hrtimeToMilliseconds(process.hrtime(this.start)));
        this.statsLoggerClient.logTimers(this.timers, this.requestTags);
    }
}
