'use strict';

const { getDocsUrl, getNodeName, scopeHasLocalReference } = require('./util');

module.exports = {
  meta: {
    docs: {
      url: getDocsUrl(__filename),
    },
    fixable: 'code',
    messages: {
      illegalGlobal:
        'Illegal usage of global `{{ global }}`, prefer `{{ replacement }}`',
      illegalMethod:
        'Illegal usage of `{{ method }}`, prefer `{{ replacement }}`',
      illegalFail:
        'Illegal usage of `fail`, prefer throwing an error, or the `done.fail` callback',
      illegalPending:
        'Illegal usage of `pending`, prefer explicitly skipping a test using `test.skip`',
      illegalJasmine: 'Illegal usage of jasmine global',
    },
  },
  create(context) {
    return {
      CallExpression(node) {
        const calleeName = getNodeName(node.callee);

        if (!calleeName) {
          return;
        }
        if (
          calleeName === 'spyOn' ||
          calleeName === 'spyOnProperty' ||
          calleeName === 'fail' ||
          calleeName === 'pending'
        ) {
          if (scopeHasLocalReference(context.getScope(), calleeName)) {
            // It's a local variable, not a jasmine global.
            return;
          }

          switch (calleeName) {
            case 'spyOn':
            case 'spyOnProperty':
              context.report({
                node,
                messageId: 'illegalGlobal',
                data: { global: calleeName, replacement: 'jest.spyOn' },
              });
              break;
            case 'fail':
              context.report({
                node,
                messageId: 'illegalFail',
              });
              break;
            case 'pending':
              context.report({
                node,
                messageId: 'illegalPending',
              });
              break;
          }
          return;
        }

        if (calleeName.startsWith('jasmine.')) {
          const functionName = calleeName.replace('jasmine.', '');

          if (
            functionName === 'any' ||
            functionName === 'anything' ||
            functionName === 'arrayContaining' ||
            functionName === 'objectContaining' ||
            functionName === 'stringMatching'
          ) {
            context.report({
              fix(fixer) {
                return [fixer.replaceText(node.callee.object, 'expect')];
              },
              node,
              messageId: 'illegalMethod',
              data: {
                method: calleeName,
                replacement: `expect.${functionName}`,
              },
            });
            return;
          }

          if (functionName === 'addMatchers') {
            context.report({
              node,
              messageId: 'illegalMethod',
              data: {
                method: calleeName,
                replacement: `expect.extend`,
              },
            });
            return;
          }

          if (functionName === 'createSpy') {
            context.report({
              node,
              messageId: 'illegalMethod',
              data: {
                method: calleeName,
                replacement: 'jest.fn',
              },
            });
            return;
          }

          context.report({
            node,
            messageId: 'illegalJasmine',
          });
        }
      },
      MemberExpression(node) {
        if (node.object.name === 'jasmine') {
          if (node.parent.type === 'AssignmentExpression') {
            if (node.property.name === 'DEFAULT_TIMEOUT_INTERVAL') {
              context.report({
                fix(fixer) {
                  return [
                    fixer.replaceText(
                      node.parent,
                      `jest.setTimeout(${node.parent.right.value})`
                    ),
                  ];
                },
                node,
                message: 'Illegal usage of jasmine global',
              });
              return;
            }

            context.report({
              node,
              message: 'Illegal usage of jasmine global',
            });
          }
        }
      },
    };
  },
};