"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

// @ts-check
// these match pino on the server-side
const levels = {
  trace: 10,
  debug: 20,
  info: 30,
  warn: 40,
  error: 50,
  fatal: 60
};

const levelToNumber = levelName => levels[levelName];
/** @typedef {'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'} LogLevel */

/**
 * @typedef {{
 *   writeToConsole?: boolean
 *   writeAsObject?: boolean
 *   level?: LogLevel
 *   beaconLevel?: LogLevel
 *   sendLogs?: boolean
 * }} LoggerOptions
 */

/** @typedef {(data, message) => void} LogFn */

/**
 * @typedef {{
 *   trace: LogFn
 *   debug: LogFn
 *   info: LogFn
 *   warn: LogFn
 *   error: LogFn
 *   fatal: LogFn
 *   child: (any) => LoggerInstance
 * }} LoggerInstance
 */

/**
 * @param {LoggerOptions} spec
 * @param {any} bindings
 * @returns {LoggerInstance}
 */


const getLogger = (spec, bindings) => {
  /** @type {LoggerOptions} */
  const options = _objectSpread({
    writeToConsole: true,
    writeAsObject: false,
    level: 'info',
    beaconLevel: 'info',
    sendLogs: true
  }, spec);

  const {
    level,
    beaconLevel,
    writeToConsole,
    sendLogs,
    writeAsObject
  } = options;
  let currentLevelAsNumber = levelToNumber(level);
  let beaconLevelAsNumber = levelToNumber(beaconLevel);

  const log = (level, metadata, message) => {
    if (typeof metadata === 'string') {
      message = metadata;
      metadata = {};
    }

    const asNumber = levelToNumber(level);
    const processedBindings = {};

    for (const key in bindings) {
      const value = bindings[key];

      try {
        processedBindings[key] = typeof value === 'function' ? value() : value;
      } catch (e) {// blank
      }
    }

    const asObject = _objectSpread(_objectSpread({
      level,
      message,
      url: location.href,
      time: Date.now()
    }, metadata), processedBindings);

    if (writeToConsole && asNumber >= currentLevelAsNumber) {
      if (writeAsObject) {
        // eslint-disable-next-line no-console
        console[level](asObject);
      } else {
        // eslint-disable-next-line no-console
        console[asObject.level](asObject.message, asObject);
      }
    }

    if (sendLogs && asNumber >= beaconLevelAsNumber) {
      try {
        // @ts-ignore
        window.__sendLog(asObject);
      } catch (e) {
        console.error('failed to send log');
      }
    }
  };

  const child = obj => getLogger(options, _objectSpread(_objectSpread({}, bindings), obj));

  const getLogFn = level => (...args) => log(level, ...args);

  return {
    trace: getLogFn('trace'),
    debug: getLogFn('debug'),
    info: getLogFn('info'),
    warn: getLogFn('warn'),
    error: getLogFn('error'),
    fatal: getLogFn('fatal'),
    child
  };
};

var _default = getLogger;
exports.default = _default;