(function (global) {
  global.ARQ = global.ARQ || {};
  /**
   * Gestor central de operaciones: emite eventos para feedback UX.
   * blocking: 'critical' (overlay modal), 'medium' (pill/spinner), 'nonblocking' (solo toast opcional)
   */
  ARQ.ops = {
    _idCounter: 0,
    _nextId: function () {
      this._idCounter += 1;
      return 'op_' + this._idCounter + '_' + Date.now();
    },

    /**
     * Ejecuta una función async con ciclo de vida de operación.
     * @param {function(): Promise<*>} fn
     * @param {{ id?: string, label: string, blocking?: string, step?: string }} opts
     */
    run: function (fn, opts) {
      opts = opts || {};
      var id = opts.id || this._nextId();
      var blocking = opts.blocking || 'nonblocking';
      var payload = {
        id: id,
        label: opts.label || 'Procesando…',
        blocking: blocking,
        step: opts.step || '',
      };
      if (typeof opts.progress === 'number' && !isNaN(opts.progress)) {
        payload.progress = opts.progress;
      }
      ARQ.bus.emit(ARQ.EVENTS.OP_STARTED, payload);
      var opCtx = { id: id, label: payload.label };
      return Promise.resolve()
        .then(function () {
          return typeof fn === 'function' ? fn(opCtx) : Promise.resolve();
        })
        .then(function (res) {
          ARQ.bus.emit(ARQ.EVENTS.OP_SUCCESS, { id: id, result: res });
          return res;
        })
        .catch(function (err) {
          var msg = err && err.message ? err.message : String(err || 'Error');
          ARQ.bus.emit(ARQ.EVENTS.OP_ERROR, { id: id, error: msg, original: err });
          throw err;
        });
    },

    /**
     * Actualiza el mensaje de una operación larga (p. ej. PDF página i/n).
     * @param {string} id
     * @param {string} label
     * @param {string} [step]
     * @param {number} [progress] 0–100 opcional (barra determinista en overlay crítico)
     */
    step: function (id, label, step, progress) {
      var payload = { id: id, label: label, step: step || '' };
      if (typeof progress === 'number' && !isNaN(progress)) payload.progress = progress;
      ARQ.bus.emit(ARQ.EVENTS.OP_STEP, payload);
    },

    emitCancelled: function (id) {
      ARQ.bus.emit(ARQ.EVENTS.OP_CANCELLED, { id: id });
    },
  };
})(typeof window !== 'undefined' ? window : this);
