import { dirname } from 'path';
import { buildExternalHelpers, transform } from 'babel-core';
import { createFilter } from 'rollup-pluginutils';
import createPreflightCheck from './preflightCheck.js';
import { warnOnce } from './utils.js';
import { RUNTIME, BUNDLED, HELPERS } from './constants.js';

const keywordHelpers = [ 'typeof', 'extends', 'instanceof' ];

export default function babel ( options ) {
	options = Object.assign( {}, options || {} );
	let inlineHelpers = {};

	const filter = createFilter( options.include, options.exclude );
	const preflightCheck = createPreflightCheck();
	delete options.include;
	delete options.exclude;

	if ( options.sourceMap !== false ) options.sourceMaps = true;
	if ( options.sourceMaps !== false ) options.sourceMaps = true;
	delete options.sourceMap;

	const runtimeHelpers = options.runtimeHelpers;
	delete options.runtimeHelpers;

	let externalHelpers;
	if ( options.externalHelpers ) externalHelpers = true;
	delete options.externalHelpers;

	let externalHelpersWhitelist = null;
	if ( options.externalHelpersWhitelist ) externalHelpersWhitelist = options.externalHelpersWhitelist;
	delete options.externalHelpersWhitelist;

	let warn = msg => console.warn(msg); // eslint-disable-line no-console

	return {
		name: 'babel',

		options ( options ) {
			warn = options.onwarn || warn;
		},

		resolveId ( id ) {
			if ( id === HELPERS ) return id;
		},

		load ( id ) {
			if ( id === HELPERS ) {
				const pattern = new RegExp( `babelHelpers\\.(${keywordHelpers.join('|')})`, 'g' );

				const helpers = buildExternalHelpers( externalHelpersWhitelist, 'var' )
					.replace(/^var babelHelpers = \{\};\n/gm, '')
					.replace(/\nbabelHelpers;$/gm, '')
					.replace( pattern, 'var _$1' )
					.replace( /^babelHelpers\./gm, 'export var ' ) +
					`\n\nexport { ${keywordHelpers.map( word => `_${word} as ${word}`).join( ', ')} }`;

				return helpers;
			}
		},

		transform ( code, id ) {
			if ( !filter( id ) ) return null;
			if ( id === HELPERS ) return null;

			const helpers = preflightCheck( options, dirname( id ) );
			const localOpts = Object.assign({ filename: id }, options );

			const transformed = transform( code, localOpts );
			const { usedHelpers } = transformed.metadata;

			if ( usedHelpers.length ) {
				if ( helpers === BUNDLED ) {
					if ( !externalHelpers ) {
						transformed.code += `\n\nimport * as babelHelpers from '${HELPERS}';`;
					}
				} else if ( helpers === RUNTIME ) {
					if ( !runtimeHelpers ) {
						throw new Error( 'Runtime helpers are not enabled. Either exclude the transform-runtime Babel plugin or pass the `runtimeHelpers: true` option. See https://github.com/rollup/rollup-plugin-babel#configuring-babel for more information' );
					}
				} else {
					usedHelpers.forEach( helper => {
						if ( inlineHelpers[ helper ] ) {
							warnOnce( warn, `The '${helper}' Babel helper is used more than once in your code. It's strongly recommended that you use the "external-helpers" plugin or the "es2015-rollup" preset. See https://github.com/rollup/rollup-plugin-babel#configuring-babel for more information` );
						}

						inlineHelpers[ helper ] = true;
					});
				}
			}

			return {
				code: transformed.code,
				map: transformed.map
			};
		}
	};
}
