import _ from 'lodash'

let appLocations = []

const requireComponent = require.context(
  // Look for files in the current directory
  './app-statuses',
  // Look in  subdirectories
  false,
  // Only include "_base-" prefixed .vue files
  /.js$/
)
// For each matching file name...
requireComponent.keys().forEach(fileName => {
  // Can use _ to turn route off
  if (fileName.indexOf('_') === -1) {
    appLocations.push(requireComponent(fileName).default)
  }
})

/**
 *  Execute outAppArea Function before browser closed
 *  collected outAppArea functions in onbeforeunloadJobs will be executed here
 *  !! caveats if user close browser without interaction beforeunload wont be triggered
 * @type {Array}
 */
let onbeforeunloadJobs = []

window.addEventListener('beforeunload', function(e) {
  if (onbeforeunloadJobs.length > 0) {
    onbeforeunloadJobs.forEach((item, index, object) => {
      Promise.resolve(item.f(item.params[0]))
      object.splice(index, 1)
    })
  }
  // Cancel the event
  e.preventDefault()
})

/**
 * The application has different functionalists when in different route locations
 * this function will loop through all the files in ./app-statuses directory and first call the {name = default}
 * objects inAppArea function. After that promise is resolved then it will loop though all the files in that directory
 * and match with the current route based on the type. eg if the [type] key of the object is path and the current path matches
 * with the [match] key of the object and if it was not matched previously then it will run inAppArea function. let say
 * if the user is in the path defined and it has run the inAppArea, then when the user leaves the route path it will
 * run outAppArea method
 * @param app
 * @param to
 * @param from
 * @returns {Promise<function(): Promise<Promise<void>[]>>}
 */
export default function(app, to, from) {
  let defaultAppSettingsIndex = _.findIndex(appLocations, ['name', 'default'])
  let defaultPromise = Promise.resolve()

  if (defaultAppSettingsIndex !== -1) {
    defaultPromise = appLocations[defaultAppSettingsIndex].inAppArea(app)
    appLocations.splice(defaultAppSettingsIndex, 1)
  }
  // after resolving the default promise, continue to the rest
  return defaultPromise.then(() => {
    let promises = [Promise.resolve()]

    appLocations.forEach(appLocation => {
      let { name, type, match, inAppArea, outAppArea } = appLocation
      let status = false
      let localMatch = []

      if (typeof match === 'string') {
        localMatch.push(match)
      } else if (typeof match === 'object') {
        localMatch = [...match]
      }

      if (typeof to[type] === 'string') {
        localMatch.forEach(m => {
          if (to[type].indexOf(m) !== -1) {
            status = true
          }
        })
      }

      if (app !== null && app.$store.getters.getAppStatus(name) !== status) {
        app.$store.dispatch('setAppStatus', { [name]: status })
        if (status) {
          // collect current appArea outAppArea function to execute later
          if (outAppArea !== undefined) {
            onbeforeunloadJobs.push({ f: outAppArea, params: [app] })
          }
          if (inAppArea !== undefined) {
            promises.push(Promise.resolve(inAppArea(app, to, from)))
          }
        } else {
          if (outAppArea !== undefined) {
            promises.push(Promise.resolve(outAppArea(app)))
          }
        }
      }
    })
    return Promise.all(promises)
  })
}
