import path from 'path';
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';
import replace from '@rollup/plugin-replace';
import copy from 'rollup-plugin-copy';
import { minify } from 'terser';

// Helpers
//
// - Display the size of a directory's content:
//   find ./dist -type f -exec stat -f"%z" {} + | awk '{s+=$1} END {print s}'

const babelOptions = {
  babelHelpers: 'bundled',
  exclude: 'node_modules/**',
  presets: [
    [
      '@babel/preset-env',
      {
        targets: { node: '10' },
        modules: false, // handle ES modules in Rollup
        useBuiltIns: false,
      },
    ],
  ],
};

// https://github.com/terser/terser#compress-options
const terserOptions = (ecma) => ({
  ecma,
  toplevel: true,
  compress: {
    ecma,
    passes: 3,
    inline: true,
    pure_getters: true,
    // use these options to find a potential for optimisations in the code
    //unsafe: true,
    //unsafe_comps: true,
  },
});

/**
 * Remove comments.
 *
 * @param {string} string
 * @return {*}
 */
function removeComments(string) {
  return string.replace(/\/\*[\s\S]*?\*\/|(?<=[^:])\/\/.*|^\/\/.*/g, '').trim();
}

function inject({ filter, code }) {
  return {
    name: 'inject',
    transform(source, id) {
      if (filter(id)) {
        return {
          code: `${code}\n${source}`,
          map: null,
        };
      }
      return null;
    },
  };
}

/**
 * Minify d.ts file content by removing comments, insignificant spaces, new lines and trailing commas.
 *
 * @param {string} content
 * @return {string}
 */
function minifyDts(content) {
  return removeComments(content)
  .replaceAll(/\n/g, '')
  .replaceAll(/\s{2,}/g, ' ')
  .replaceAll(': ', ':')
  .replaceAll(' | ', '|')
  .replaceAll(' & ', '&')
  .replaceAll(' = ', '=')
  .replaceAll(' =', '=')
  .replaceAll('=|', '=')
  .replaceAll('=> ', '=>')
  .replaceAll(', ', ',')
  .replaceAll('{ ', '{')
  .replaceAll(' {', '{')
  .replaceAll(' }', '}')
  .replaceAll('; ', ';')
  .replaceAll(' ;', ';')
  .replaceAll(',}', '}')
  .replaceAll(';}', '}');
}

function buildConfig({ output, ecma }) {
  return {
    input: 'src/index.js',
    output: {
      file: `dist/${output}/index.cjs`,
      format: 'cjs',
      exports: 'named',
      intro: '/* Auto generated by rollup.\nUse `npm run build` to create new version. */',
      strict: false,
      esModule: false,
    },
    plugins: [
      ...(ecma < 2020
        ? [
          inject({
            filter: id => path.resolve(id).endsWith('src/index.js'),
            code: `typeof globalThis === 'undefined' && (global.globalThis = global);`,
          })
        ]
        : []),
      replace({
        // allow modifying exports
        preventAssignment: false,
        // the order of exports is other than is needed
        // firstly must be defined default export
        'exports.Ansis = Ansis': 'module.exports = ansis',
        // then on the next line can be named and default export,
        // `ansis.default = ansis` is needed for tsc using default import, e.g. `import ansis from 'ansis'`
        'exports.default = ansis': 'ansis.default = ansis',

        // required for Node.js 10
        //'/* @node10:polyfills */': "typeof globalThis === 'undefined' && (global.globalThis = global);"
        //'globalThis': "typeof globalThis === 'undefined' && (global.globalThis = global);"
        //'globalThis': "typeof globalThis === 'undefined' ? global : globalThis"
        //'globalThis': "'QWERTZ'"
        //...(ecma < 2020 ? {'globalThis': "typeof globalThis === 'undefined' ? global : globalThis"} : {})
      }),
      ...(ecma < 2020 ? [babel(babelOptions)] : []),
      terser(terserOptions(ecma)),
      copy({
        targets: [
          {
            src: 'src/index.mjs',
            dest: `dist/${output}/`,
            transform: async (contents) => (
              await minify(
                // transform the extension of the source ESM file to output .cjs (it will be compiled to CommonJS)
                contents.toString().replace('.js', '.cjs'),
                { ecma }
              )
            ).code,
          },
          {
            src: 'src/index.d.ts',
            dest: `dist/${output}/`,
            rename: 'index.d.ts',
            transform: (contents) => minifyDts(contents.toString()),
          },
          { src: `package.npm-${output}.json`, dest: `dist/${output}/`, rename: 'package.json' },
          { src: `README.npm-${output}.md`, dest: `dist/${output}/`, rename: 'README.md' },
          { src: 'LICENSE', dest: `dist/${output}/` },
        ],
      }),
    ],
  };
}

export default [
  buildConfig({ output: 'node10', ecma: 2018 }), // ES9 (ES2018), Node.js 10+
  buildConfig({ output: 'node14', ecma: 2020 }), // ES11 (ES2020), Node.js 14+
];
