/*
 * Since AngularJS 1.5, we can use a new API when creating directives.
 * This new API should be use when creating directive without DOM manipulation.
 *
 * @version 0.16.0
 * @category bestPractice
 * @sinceAngularVersion 1.5
 */
'use strict';

var angularRule = require('./utils/angular-rule');
var allowedProperties = ['compile', 'link', 'multiElement', 'priority', 'templateNamespace', 'terminal'];

module.exports = {
    meta: {
        docs: {
            url: 'https://github.com/Gillespie59/eslint-plugin-angular/blob/master/docs/rules/prefer-component.md'
        },
        schema: []
    },
    create: angularRule(function(context) {
        var potentialReplaceNodes = {};

        function addPotentialLinkNode(variableName, node) {
            var nodeList = potentialReplaceNodes[variableName] || [];

            nodeList.push({
                name: variableName,
                node: node,
                block: context.sourceCode.getScope(node).block.body
            });

            potentialReplaceNodes[variableName] = nodeList;
        }

        return {
            'angular?directive': function(callExpressionNode, fnNode) {
                if (!fnNode || !fnNode.body) {
                    return;
                }
                fnNode.body.body.forEach(function(statement) {
                    if (statement.type === 'ReturnStatement' && !potentialReplaceNodes[statement.argument.name || '']) {
                        context.report(statement, 'Directive should be implemented with the component method.');
                    }
                });
            },
            AssignmentExpression: function(node) {
                // Only check for literal member property assignments.
                if (node.left.type !== 'MemberExpression') {
                    return;
                }

                if (allowedProperties.indexOf(node.left.property.name) < 0) {
                    return;
                }

                addPotentialLinkNode(node.left.object.name, node);
            },
            Property: function(node) {
                if (node.key.name === 'restrict') {
                    if (node.value.raw && node.value.raw.indexOf('C') < 0 && node.value.raw.indexOf('A') < 0) {
                        return;
                    }
                } else if (allowedProperties.indexOf(node.key.name) < 0) {
                    return;
                }

                // assumption: Property always belongs to a ObjectExpression
                var objectExpressionParent = node.parent.parent;

                // add to potential link nodes if the object is defined in a variable
                if (objectExpressionParent.type === 'VariableDeclarator') {
                    addPotentialLinkNode(objectExpressionParent.id.name, node);
                }

                // report directly if object is part of a return statement and inside a directive body
                if (objectExpressionParent.type === 'ReturnStatement') {
                    addPotentialLinkNode('', node);
                }
            }
        };
    })
};
