/**
 * @fileoverview Ensures consistent parameter names in blaze event maps
 * @author Philipp Sporrer
 * @copyright 2015 Philipp Sporrer. All rights reserved.
 * See LICENSE file in root directory for full license.
 */

import {isFunction} from '../util/ast'
import {getExecutors} from '../util'

// -----------------------------------------------------------------------------
// Rule Definition
// -----------------------------------------------------------------------------

module.exports = getMeta => context => {

  const {env, isLintedEnv} = getMeta(context.getFilename())

  if (!isLintedEnv) {
    return {}
  }

  // ---------------------------------------------------------------------------
  // Helpers
  // ---------------------------------------------------------------------------

  function ensureParamName (node, paramIndex, expectedParamName) {
    const param = node.params[paramIndex]
    if (param && param.name !== expectedParamName) {
      context.report(
        param,
        `Invalid parameter name, use "${expectedParamName}" instead`
      )
    }
  }

  function validateEventDef (eventDefNode, executors) {

    if (executors.has('server')) {
      return context.report(
        eventDefNode,
        `Allowed on client only`
      )
    }

    // check if the event definition has a value
    const eventHandler = eventDefNode.value
    // check if the event definition's value is a function
    // (aka the event handler)
    if (isFunction(eventHandler.type)) {
      // check if the first parameter name is equal to 'event'
      ensureParamName(
        eventHandler,
        0,
        context.options[0] ? context.options[0].eventParamName : 'event'
      )
      // check if the second parameter name is equal to 'event'
      ensureParamName(
        eventHandler,
        1,
        context.options[0] ? context.options[0].templateInstanceParamName : 'templateInstance'
      )
    }

  }

  // ---------------------------------------------------------------------------
  // Public
  // ---------------------------------------------------------------------------

  return {

    CallExpression(node) {

      const ancestors = context.getAncestors()
      const executors = getExecutors(env, ancestors)
      // check if the Template.x.events(/*eventMap*/) call got any arguments
      if (node.arguments.length > 0) {
        const eventMap = node.arguments[0]
        // check if the event map argument is an object
        if (
          eventMap.type === 'ObjectExpression'
        ) {
          eventMap.properties.forEach((eventDef) => validateEventDef(eventDef, executors))
        }
      }

    }

  }

}

module.exports.schema = [
  {
    type: 'object',
    properties: {
      eventParamName: {
        type: 'string'
      },
      templateInstanceParamName: {
        type: 'string'
      }
    },
    additionalProperties: false
  }
]

@@ -825,24 +825,13 @@
 me (
-node, paramIndex
+param
 , ex
@@ -853,50 +853,8 @@
 ) %7B%0A
-    const param = node.params%5BparamIndex%5D%0A
     
@@ -1552,19 +1552,18 @@
 dler
-,%0A        0
+.params%5B0%5D
 ,%0A  
@@ -1752,19 +1752,18 @@
 dler
-,%0A        1
+.params%5B1%5D
 ,%0A  

refactor method to be simpler ensureParamName does not get the whole node with all the params, but only the param that it needs