import { EVT_SESSION_EXPIRED as s, EVT_SESSION_REFRESHING_START as r, EVT_SESSION_REFRESHING_END as _, EVT_SESSION_REFRESHED as h, EVT_SESSION_READY as n, ERR_SESSION_HTTP_UNAVAILABLE as E, ERR_SESSION_EXPIRED as o } from "./constants.js";
import { INTERNAL_EVT_SESSION_DEADLINE as S, INTERNAL_EVT_SESSION_REFRESHING_START as f, INTERNAL_EVT_SESSION_REFRESHING_END as a, INTERNAL_EVT_SESSION_READY as m } from "./internal/constants.js";
import { createSessionAutofresher as p } from "./internal/autofresher.js";
import { createSessionDeadline as N } from "./internal/deadline.js";
import { createSessionRefresher as c } from "./internal/refresher.js";
import { createEventEmitter as R } from "../../reactive/eventEmitter/main.js";
import { isFunction as I } from "../../../utils/value/is.js";
import { noop as d } from "../../../utils/common.js";
class L {
  constructor(e) {
    this._specification = e, this._deadline = N(this._eventEmitter, this._specification), this._refresher = c(this._eventEmitter, this._specification), this._autofresh = p(this._refresher), this._deadline.on(S, () => this._eventEmitter.emit(s)), this._refresher.on(f, () => this._eventEmitter.emit(r)), this._refresher.on(a, () => this._eventEmitter.emit(_)), this._refresher.on(m, () => {
      this._session = this._refresher.session, this._deadline.refresh(this._session).finally(() => this._eventEmitter.emit(h)), this._eventEmitter.emit(n);
    }), this.http = this._sessionHttp.bind(this), this.on = this._eventEmitter.on, this.refresh = this._refresher.refresh;
  }
  _session;
  _autofresh;
  _deadline;
  _refresher;
  _eventEmitter = R();
  get isExpired() {
    return this._deadline.elapsed;
  }
  get refreshing() {
    return this._refresher.refreshing;
  }
  _assertSessionHttp(e) {
    if (!I(e)) throw E;
  }
  async _sessionHttp(e, ...i) {
    for (this._autofresh(!0); ; )
      try {
        await this._refresher.promise.catch(d);
        const { signal: t } = this._deadline;
        return await e?.(this._session, t, ...i), this._assertSessionHttp(this._specification.http), await this._specification.http(this._session, t, ...i);
      } catch (t) {
        if (t !== o) throw t;
        if (this._refresher.pending) continue;
        this._deadline.elapse();
      }
  }
}
export {
  L as SessionContext
};
