module.exports = function(session) {
  const Store = session.Store

  const defer = (cb, ...args) => {
    if (typeof cb != 'function') return
    setImmediate(cb, ...args)
  }

  class ExtendedMap extends Map {
    set(key, value, maxAge) {
      const cached = super.get(key)
      if (cached && cached.timer) clearTimeout(cached.timer)
      const timer = maxAge ? setTimeout(super.delete.bind(this, key), maxAge) : null
      return super.set(key, {timer, value})
    }
  
    get(key) {
      const cached = super.get(key)
      return cached && cached.value
    }
  
    delete(key) {
      const cached = super.get(key)
      if (cached && cached.timer) clearTimeout(cached.timer)
      return super.delete(key)
    }
  }

  class MemoryStore extends Store {
    constructor(options = {}) {
      super(options)
      this.sessions = new ExtendedMap()
      this.ttl = options.ttl
    }

    get(sid, callback) {
      let session = this.sessions.get(sid)
      defer(callback, null, session)
    }

    set(sid, session, callback) {
      let ttl = this._getTTL(session)
      if (ttl > 0) {
        this.sessions.set(sid, session, ttl)
      } else {
        this.sessions.delete(sid)
      }
      defer(callback, null)
    }

    touch(sid, session, callback) {
      let ttl = this._getTTL(session)
      let stored = this.sessions.get(sid)
      stored.cookie = session.cookie
      this.sessions.set(sid, stored, ttl)
      defer(callback, null)
    }

    destroy(sid, callback) {
      this.sessions.delete(sid)
      defer(callback, null)
    }

    clear(callback) {
      this.sessions.clear()
      defer(callback, null)
    }

    length(callback) {
      let len = this.sessions.size
      defer(callback, null, len)
    }

    ids(callback) {
      let keys = Array.from(this.sessions.keys())
      defer(callback, null, keys)
    }

    all(callback) {
      let sessions = Array.from(this.sessions.values())
      defer(callback, null, sessions)
    }

    _getTTL(session) {
      if (typeof this.ttl == 'number') return this.ttl
      let maxAge = (session && session.cookie) ? session.cookie.maxAge : null
      return (typeof maxAge == 'number') ? maxAge : 86400000
    }
  }

  return MemoryStore
}