"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.zip = exports.withNow = exports.withConstantInput = exports.value = exports.update = exports.unsafeSnapshot = exports.trackSuccessWith = exports.trackSuccess = exports.trackErrorWith = exports.trackError = exports.trackDurationWith = exports.trackDuration = exports.trackDefectWith = exports.trackDefect = exports.trackAll = exports.timerWithBoundaries = exports.timer = exports.taggedWithLabelsInput = exports.taggedWithLabels = exports.tagged = exports.sync = exports.summaryTimestamp = exports.summary = exports.succeed = exports.snapshot = exports.set = exports.mapType = exports.mapInput = exports.map = exports.make = exports.incrementBy = exports.increment = exports.histogram = exports.globalMetricRegistry = exports.gauge = exports.fromMetricKey = exports.frequency = exports.counter = exports.MetricTypeId = void 0;
var Array = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Array.js"));
var Clock = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Clock.js"));
var Duration = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Duration.js"));
var _Function = /*#__PURE__*/require("../Function.js");
var _GlobalValue = /*#__PURE__*/require("../GlobalValue.js");
var _Pipeable = /*#__PURE__*/require("../Pipeable.js");
var Cause = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./cause.js"));
var _effect = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./core-effect.js"));
var core = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./core.js"));
var metricBoundaries = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./metric/boundaries.js"));
var metricKey = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./metric/key.js"));
var metricLabel = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./metric/label.js"));
var metricRegistry = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./metric/registry.js"));
function _getRequireWildcardCache(e) {
  if ("function" != typeof WeakMap) return null;
  var r = new WeakMap(),
    t = new WeakMap();
  return (_getRequireWildcardCache = function (e) {
    return e ? t : r;
  })(e);
}
function _interopRequireWildcard(e, r) {
  if (!r && e && e.__esModule) return e;
  if (null === e || "object" != typeof e && "function" != typeof e) return {
    default: e
  };
  var t = _getRequireWildcardCache(r);
  if (t && t.has(e)) return t.get(e);
  var n = {
      __proto__: null
    },
    a = Object.defineProperty && Object.getOwnPropertyDescriptor;
  for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) {
    var i = a ? Object.getOwnPropertyDescriptor(e, u) : null;
    i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u];
  }
  return n.default = e, t && t.set(e, n), n;
}
/** @internal */
const MetricSymbolKey = "effect/Metric";
/** @internal */
const MetricTypeId = exports.MetricTypeId = /*#__PURE__*/Symbol.for(MetricSymbolKey);
const metricVariance = {
  /* c8 ignore next */
  _Type: _ => _,
  /* c8 ignore next */
  _In: _ => _,
  /* c8 ignore next */
  _Out: _ => _
};
/** @internal */
const globalMetricRegistry = exports.globalMetricRegistry = /*#__PURE__*/(0, _GlobalValue.globalValue)( /*#__PURE__*/Symbol.for("effect/Metric/globalMetricRegistry"), () => metricRegistry.make());
/** @internal */
const make = function (keyType, unsafeUpdate, unsafeValue) {
  const metric = Object.assign(effect => core.tap(effect, a => update(metric, a)), {
    [MetricTypeId]: metricVariance,
    keyType,
    unsafeUpdate,
    unsafeValue,
    register() {
      this.unsafeValue([]);
      return this;
    },
    pipe() {
      return (0, _Pipeable.pipeArguments)(this, arguments);
    }
  });
  return metric;
};
/** @internal */
exports.make = make;
const mapInput = exports.mapInput = /*#__PURE__*/(0, _Function.dual)(2, (self, f) => make(self.keyType, (input, extraTags) => self.unsafeUpdate(f(input), extraTags), self.unsafeValue));
/** @internal */
const counter = (name, options) => fromMetricKey(metricKey.counter(name, options));
/** @internal */
exports.counter = counter;
const frequency = (name, options) => fromMetricKey(metricKey.frequency(name, options));
/** @internal */
exports.frequency = frequency;
const withConstantInput = exports.withConstantInput = /*#__PURE__*/(0, _Function.dual)(2, (self, input) => mapInput(self, () => input));
/** @internal */
const fromMetricKey = key => {
  let untaggedHook;
  const hookCache = new WeakMap();
  const hook = extraTags => {
    if (extraTags.length === 0) {
      if (untaggedHook !== undefined) {
        return untaggedHook;
      }
      untaggedHook = globalMetricRegistry.get(key);
      return untaggedHook;
    }
    let hook = hookCache.get(extraTags);
    if (hook !== undefined) {
      return hook;
    }
    hook = globalMetricRegistry.get(metricKey.taggedWithLabels(key, extraTags));
    hookCache.set(extraTags, hook);
    return hook;
  };
  return make(key.keyType, (input, extraTags) => hook(extraTags).update(input), extraTags => hook(extraTags).get());
};
/** @internal */
exports.fromMetricKey = fromMetricKey;
const gauge = (name, options) => fromMetricKey(metricKey.gauge(name, options));
/** @internal */
exports.gauge = gauge;
const histogram = (name, boundaries, description) => fromMetricKey(metricKey.histogram(name, boundaries, description));
/* @internal */
exports.histogram = histogram;
const increment = self => update(self, self.keyType.bigint ? BigInt(1) : 1);
/* @internal */
exports.increment = increment;
const incrementBy = exports.incrementBy = /*#__PURE__*/(0, _Function.dual)(2, (self, amount) => update(self, amount));
/** @internal */
const map = exports.map = /*#__PURE__*/(0, _Function.dual)(2, (self, f) => make(self.keyType, self.unsafeUpdate, extraTags => f(self.unsafeValue(extraTags))));
/** @internal */
const mapType = exports.mapType = /*#__PURE__*/(0, _Function.dual)(2, (self, f) => make(f(self.keyType), self.unsafeUpdate, self.unsafeValue));
/* @internal */
const set = exports.set = /*#__PURE__*/(0, _Function.dual)(2, (self, value) => update(self, value));
/** @internal */
const succeed = out => make(void 0, _Function.constVoid, () => out);
/** @internal */
exports.succeed = succeed;
const sync = evaluate => make(void 0, _Function.constVoid, evaluate);
/** @internal */
exports.sync = sync;
const summary = options => withNow(summaryTimestamp(options));
/** @internal */
exports.summary = summary;
const summaryTimestamp = options => fromMetricKey(metricKey.summary(options));
/** @internal */
exports.summaryTimestamp = summaryTimestamp;
const tagged = exports.tagged = /*#__PURE__*/(0, _Function.dual)(3, (self, key, value) => taggedWithLabels(self, [metricLabel.make(key, value)]));
/** @internal */
const taggedWithLabelsInput = exports.taggedWithLabelsInput = /*#__PURE__*/(0, _Function.dual)(2, (self, f) => map(make(self.keyType, (input, extraTags) => self.unsafeUpdate(input, Array.union(f(input), extraTags)), self.unsafeValue), _Function.constVoid));
/** @internal */
const taggedWithLabels = exports.taggedWithLabels = /*#__PURE__*/(0, _Function.dual)(2, (self, extraTags) => {
  return make(self.keyType, (input, extraTags1) => self.unsafeUpdate(input, Array.union(extraTags, extraTags1)), extraTags1 => self.unsafeValue(Array.union(extraTags, extraTags1)));
});
/** @internal */
const timer = (name, description) => {
  const boundaries = metricBoundaries.exponential({
    start: 0.5,
    factor: 2,
    count: 35
  });
  const base = (0, _Function.pipe)(histogram(name, boundaries, description), tagged("time_unit", "milliseconds"));
  return mapInput(base, Duration.toMillis);
};
/** @internal */
exports.timer = timer;
const timerWithBoundaries = (name, boundaries, description) => {
  const base = (0, _Function.pipe)(histogram(name, metricBoundaries.fromIterable(boundaries), description), tagged("time_unit", "milliseconds"));
  return mapInput(base, Duration.toMillis);
};
/* @internal */
exports.timerWithBoundaries = timerWithBoundaries;
const trackAll = exports.trackAll = /*#__PURE__*/(0, _Function.dual)(2, (self, input) => effect => core.matchCauseEffect(effect, {
  onFailure: cause => core.zipRight(update(self, input), core.failCause(cause)),
  onSuccess: value => core.zipRight(update(self, input), core.succeed(value))
}));
/* @internal */
const trackDefect = exports.trackDefect = /*#__PURE__*/(0, _Function.dual)(2, (self, metric) => trackDefectWith(self, metric, _Function.identity));
/* @internal */
const trackDefectWith = exports.trackDefectWith = /*#__PURE__*/(0, _Function.dual)(3, (self, metric, f) => {
  const updater = defect => update(metric, f(defect));
  return _effect.tapDefect(self, cause => core.forEachSequentialDiscard(Cause.defects(cause), updater));
});
/* @internal */
const trackDuration = exports.trackDuration = /*#__PURE__*/(0, _Function.dual)(2, (self, metric) => trackDurationWith(self, metric, _Function.identity));
/* @internal */
const trackDurationWith = exports.trackDurationWith = /*#__PURE__*/(0, _Function.dual)(3, (self, metric, f) => Clock.clockWith(clock => {
  const startTime = clock.unsafeCurrentTimeNanos();
  return core.tap(self, _ => {
    const endTime = clock.unsafeCurrentTimeNanos();
    const duration = Duration.nanos(endTime - startTime);
    return update(metric, f(duration));
  });
}));
/* @internal */
const trackError = exports.trackError = /*#__PURE__*/(0, _Function.dual)(2, (self, metric) => trackErrorWith(self, metric, a => a));
/* @internal */
const trackErrorWith = exports.trackErrorWith = /*#__PURE__*/(0, _Function.dual)(3, (self, metric, f) => {
  const updater = error => update(metric, f(error));
  return _effect.tapError(self, updater);
});
/* @internal */
const trackSuccess = exports.trackSuccess = /*#__PURE__*/(0, _Function.dual)(2, (self, metric) => trackSuccessWith(self, metric, a => a));
/* @internal */
const trackSuccessWith = exports.trackSuccessWith = /*#__PURE__*/(0, _Function.dual)(3, (self, metric, f) => {
  const updater = value => update(metric, f(value));
  return core.tap(self, updater);
});
/* @internal */
const update = exports.update = /*#__PURE__*/(0, _Function.dual)(2, (self, input) => core.fiberRefGetWith(core.currentMetricLabels, tags => core.sync(() => self.unsafeUpdate(input, tags))));
/* @internal */
const value = self => core.fiberRefGetWith(core.currentMetricLabels, tags => core.sync(() => self.unsafeValue(tags)));
/** @internal */
exports.value = value;
const withNow = self => mapInput(self, input => [input, Date.now()]);
/** @internal */
exports.withNow = withNow;
const zip = exports.zip = /*#__PURE__*/(0, _Function.dual)(2, (self, that) => make([self.keyType, that.keyType], (input, extraTags) => {
  const [l, r] = input;
  self.unsafeUpdate(l, extraTags);
  that.unsafeUpdate(r, extraTags);
}, extraTags => [self.unsafeValue(extraTags), that.unsafeValue(extraTags)]));
/** @internal */
const unsafeSnapshot = () => globalMetricRegistry.snapshot();
/** @internal */
exports.unsafeSnapshot = unsafeSnapshot;
const snapshot = exports.snapshot = /*#__PURE__*/core.sync(unsafeSnapshot);
//# sourceMappingURL=metric.js.map