/**
 * Async lock utility - Promise-based mutex per key.
 * Ensures only one async operation executes per key at a time.
 */

const locks = new Map()

/**
 * Get or create a queue for a lock key.
 * @param {string} lockKey - Lock key
 * @returns {Promise<any>} Existing or new queue promise
 */
const getOrCreateQueue = (lockKey) => {
  const existingQueue = locks.get(lockKey)
  if (existingQueue) return existingQueue
  const newQueue = Promise.resolve()
  locks.set(lockKey, newQueue)
  return newQueue
}

/**
 * Acquire a lock for a key and execute callback.
 * Only one callback per key executes at a time.
 * @param {string} key - Lock key
 * @param {Function} callback - Async function to execute
 * @returns {Promise<any>} Result of callback
 */
export async function acquire(key, callback) {
  const lockKey = String(key)
  const queue = getOrCreateQueue(lockKey)

  const next = queue.then(() => callback()).finally(() => {
    if (locks.get(lockKey) === next) {
      locks.delete(lockKey)
    }
  })

  locks.set(lockKey, next)
  return next
}

/**
 * Clear all locks (for testing).
 */
export function clearLocks() {
  locks.clear()
}
