Promise = require('bluebird')
FS = require('fs')

Base = require('../base')
Caller = require('./caller')


debug = Base.logger('nodejs_exports_loader')


exports.loadIxExports = (ixApiDir) ->
  exportInfo = {}
  exportedProps = {}
  ixDirname = ixApiDir || Base.env.IX_API_DIR || 'faas-ix'
  ixDir = process.cwd()+'/'+ixDirname
  Promise.fromCallback (callback) ->
    FS.readdir(ixDir, callback)
  .then (files) ->
    debug('readdir', files)
    for file in files
      path = ixDir+'/'+file
      try
        if file.match(/\w$/) # Don't load auto-save files.
          fexports = require(path) # Supports files and module directories.
          debug('file', file, fexports)
          modName = file
          modName = modName.replace(/\.(js|json|node)$/i, '')
          modName = modName.replace(/\W/g, '_')
          meta = exportInfo[modName]
          if exportInfo[modName]
            console.log("Multiple definitions found for module '"+modName+"', only using definitions from file '"+meta.file+"' (discarding '"+file+"').")
          else
            exportInfo[modName] = { file: file, exports: metaForObj(fexports) }
            exportedProps[modName] = fexports
      catch e
        console.log('Unable to load module '+path+':', e)
    debug('exportInfo', JSON.stringify(exportInfo))
    Caller.setNodejsExports(exportedProps)
    exportInfo

metaForObj = (obj) ->
  if Base.utils.isFobject(obj)
    info = { isFunc: Base.utils.isFunction(obj) } # Top-level function.
    for own attName, att of obj
      info.atts ||= {}
      metaInfo = metaForObj(att)
      info.atts[attName] = metaInfo
  else # Non-object property.
    info = { value: obj }
  # TODO: How to tell if it needs to be invoked with a callback? sync or async?
  info
