ConnectionStates =
  disconnected  : 0
  connected     : 1
  connecting    : 2
  disconnecting : 3

module.exports = (mongoose) ->
  throw new Error('Mongoose is a required argument for mongoose-connection-manager!') unless mongoose?

  connections: {}
  callbacks: []
  logger: null

  get: (name) ->
    @connections[name]

  exists: (name) ->
    @connections[name]?

  create: (name, settings) ->
    throw new Error "Connection name must be provided" unless name?
    throw new Error "Connection settings must be provided" unless settings?
    throw new Error "Connection url must be provided" unless settings.url

    if settings.useDefault
      @connections[name] = mongoose.connection
    else
      @connections[name] = mongoose.createConnection()

    @connections[name].settings = settings
    @connections[name]

  setLogger: (newLogger) ->
    @logger = newLogger

  connect: () ->
    if @allConnected()
      return

    connectTo = (name, settings) =>
      url = settings.url
      options = settings.options ? {}
      logger = settings.logger ? @logger

      try
        await @connections[name].openUri(url, options)
      catch err
        logger?.error err, "Failed to connect to `#{name}` database on startup - retrying in 5 sec"

        await new Promise (resolve) =>
          setTimeout (-> resolve()), 5000

        try
          await connectTo(name, settings)
        catch err
          logger?.error err, "Retry failed for `#{name}`"

    for name, connection of @connections
      switch connection.readyState
        when ConnectionStates.disconnected
          await connectTo name, connection.settings
        when ConnectionStates.disconnecting
          throw new Error "Called connect() before disconnect() has finished"

  allConnected: ->
    Object.keys(@connections).every (connection) =>
      @connections[connection].readyState is ConnectionStates.connected

  disconnect: ->
    await mongoose.disconnect()
