function CacheUntilResolved(_target, propertyKey, descriptor) {
  const promiseMap = /* @__PURE__ */ new Map();
  const originalMethod = descriptor.value;
  descriptor.value = function(...args) {
    const key = `${propertyKey}_${JSON.stringify(args)}`;
    if (promiseMap.has(key)) {
      return promiseMap.get(key);
    }
    const resultPromise = originalMethod.apply(this, args);
    promiseMap.set(key, resultPromise);
    resultPromise.finally(() => {
      promiseMap.delete(key);
    });
    return resultPromise;
  };
  return descriptor;
}
function Debounce(delay = 300) {
  return function(_target, _propertyKey, descriptor) {
    const originalMethod = descriptor.value;
    let timeoutId;
    descriptor.value = function(...args) {
      if (timeoutId) {
        clearTimeout(timeoutId);
      }
      timeoutId = window.setTimeout(() => {
        originalMethod.apply(this, args);
      }, delay);
    };
    return descriptor;
  };
}
function ImmutableArgs(_target, _propertyKey, descriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function(...args) {
    const changedArgs = args.map((arg) => {
      if (arg && typeof arg === "object") {
        arg = JSON.parse(JSON.stringify(arg));
      }
      return arg;
    });
    return originalMethod.apply(this, changedArgs);
  };
  return descriptor;
}
function Memoize(_target, _key, descriptor) {
  const originalMethod = descriptor.value;
  const cache = /* @__PURE__ */ new Map();
  const maxSize = 500;
  descriptor.value = function value(...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      const cacheValue = cache.get(key);
      cache.delete(key);
      cache.set(key, cacheValue);
      return cacheValue;
    }
    const result = originalMethod.call(this, ...args);
    cache.set(key, result);
    if (cache.size > maxSize) {
      const firstKey = cache.keys().next().value;
      cache.delete(firstKey);
    }
    return result;
  };
}
function MemoizeAsync(_target, _propertyKey, descriptor) {
  const originalMethod = descriptor.value || descriptor.get;
  const cache = /* @__PURE__ */ new Map();
  if (typeof originalMethod !== "function") {
    throw new Error("Decorator can only be applied to methods or getters");
  }
  if (descriptor.value) {
    descriptor.value = async function(...args) {
      const cacheKey = JSON.stringify(args);
      if (cache.has(cacheKey)) {
        return cache.get(cacheKey);
      }
      const resultPromise = originalMethod.apply(this, args);
      cache.set(cacheKey, resultPromise);
      try {
        const result = await resultPromise;
        return result;
      } catch (error) {
        cache.delete(cacheKey);
        throw error;
      }
    };
  } else if (descriptor.get) {
    descriptor.get = async function() {
      const cacheKey = "getter";
      if (cache.has(cacheKey)) {
        return cache.get(cacheKey);
      }
      const resultPromise = originalMethod.apply(this);
      cache.set(cacheKey, resultPromise);
      try {
        const result = await resultPromise;
        return result;
      } catch (error) {
        cache.delete(cacheKey);
        throw error;
      }
    };
  }
  return descriptor;
}
function QueueTask(_target, _key, descriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function value(...args) {
    queueMicrotask(() => {
      originalMethod.call(this, ...args);
    });
  };
}
function Throttle(delay = 300) {
  let lastCall = 0;
  return function(_target, _propertyKey, descriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function(...args) {
      const now = Date.now();
      if (now - lastCall >= delay) {
        lastCall = now;
        originalMethod.apply(this, args);
      }
    };
    return descriptor;
  };
}
function AsyncSingleExecution(_target, _propertyKey, descriptor) {
  const originalMethod = descriptor.value;
  const instanceMap = /* @__PURE__ */ new WeakMap();
  descriptor.value = function(...args) {
    const instance = this;
    if (!instanceMap.has(instance)) {
      instanceMap.set(instance, /* @__PURE__ */ new Map());
    }
    const promiseMap = instanceMap.get(instance);
    const key = JSON.stringify(args);
    if (promiseMap.has(key)) {
      return promiseMap.get(key);
    }
    const promise = originalMethod.apply(this, args);
    if (promise && typeof promise.then === "function") {
      promiseMap.set(key, promise);
      promise.catch((e) => e).finally(() => {
        promiseMap.delete(key);
      });
    }
    return promise;
  };
  return descriptor;
}
function RetryAsync(retries = 3, interval = 2e3, reThrowException = true) {
  return function(_target, _propertyKey, descriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = async function(...args) {
      let attempts = 0;
      while (attempts < retries) {
        try {
          const result = originalMethod.apply(this, args);
          if (result && typeof result.then === "function") {
            return await result;
          }
          return result;
        } catch (error) {
          attempts += 1;
          if (attempts >= retries) {
            if (reThrowException) {
              throw error;
            }
            return void 0;
          }
          await new Promise((resolve) => {
            setTimeout(() => {
              resolve(true);
            }, interval);
          });
        }
      }
      return void 0;
    };
    return descriptor;
  };
}
function MemoizeSingleArgPrimitive(_target, _propertyKey, descriptor) {
  const originalMethod = descriptor.value;
  const cache = {};
  function isPrimitiveArg(arg) {
    const type = typeof arg;
    return arg === null || type === "string" || type === "number" || type === "boolean" || type === "symbol" || type === "undefined";
  }
  function getCachedResult(params) {
    const { context, cacheObj, key, original, arg } = params;
    if (Object.prototype.hasOwnProperty.call(cacheObj, key)) {
      return cacheObj[key];
    }
    const result = arg !== void 0 ? original.call(context, arg) : original.call(context);
    cacheObj[key] = result;
    return result;
  }
  descriptor.value = function MemoizeSingleArgPrimitiveWrapper(...args) {
    if (args.length === 0) {
      return getCachedResult({
        context: this,
        cacheObj: cache,
        key: "__NO_ARGS__",
        original: originalMethod
      });
    }
    if (args.length === 1 && isPrimitiveArg(args[0])) {
      const key = String(args[0]);
      return getCachedResult({
        context: this,
        cacheObj: cache,
        key,
        original: originalMethod,
        arg: args[0]
      });
    }
    return originalMethod.apply(this, args);
  };
  return descriptor;
}
export {
  AsyncSingleExecution,
  CacheUntilResolved,
  Debounce,
  ImmutableArgs,
  Memoize,
  MemoizeAsync,
  MemoizeSingleArgPrimitive,
  QueueTask,
  RetryAsync,
  Throttle
};
