import Berun from '@berun/berun'

// FIX-DEPENDENCIES
require.resolve('babel-loader')
require.resolve('@svgr/webpack')
require.resolve('url-loader')
require.resolve('file-loader')

/**
 *  Disable require.ensure as it's not a standard language feature.
 */
export const ruleParser = (berun: Berun, _) => {
  berun.webpack.module.rule('parser').parser({ requireEnsure: false }).end()
}

/**
 * `mjs` support is still in its infancy in the ecosystem, so we don't
 * support it.
 * Modules who define their `browser` or `module` key as `mjs` force
 * the use of this extension, so we need to tell webpack to fall back
 * to auto mode (ES Module interop, allows ESM to import CommonJS).
 */
export const ruleMjs = (berun: Berun, _) => {
  berun.webpack.module
    .rule('mjs')
    .test([/\.mjs$/])
    .include.add(/node_modules/)
    .end()
    .type('javascript/auto')
    .use('babel')
    .loader(require.resolve('babel-loader'))
    .options({
      babelrc: false,
      configFile: false,
      compact: false,
      presets: [
        require.resolve('@berun/babel-preset-react-app/dist/dependencies')
      ],
      cacheDirectory: true,
      cacheCompression: process.env.NODE_ENV === 'production',
      highlightCode: true,
      sourceMaps: false
    })
}

/**
 * "url" loader works like "file" loader except that it embeds assets
 * smaller than specified limit in bytes as data URLs to avoid requests.
 * A missing `test` is equivalent to a match.
 */
export const ruleMainImage = (berun: Berun, _) => {
  berun.webpack.module
    .rule('main')
    .oneOf('image')
    .test([/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/])
    .exclude.add(/node_modules/)
    .end()
    .use('url-loader')
    .loader(require.resolve('url-loader'))
    .options({ limit: 10000, name: 'static/media/[name].[hash:8].[ext]' })
}

/**
 * Process application JS with Babel.
 * The preset includes JSX, Flow, and some ESnext features.
 */
export const ruleMainCompile = (berun: Berun, _) => {
  berun.webpack.module
    .rule('main')
    .oneOf('compile')
    .test(/\.(js|jsx|ts|tsx)$/)
    .include.merge([berun.options.paths.metaWorkspace])
    .end()
    .exclude.add(/node_modules/)
    .end()
    .use('babel')
    .loader(require.resolve('babel-loader'))
    .options({
      /* placeholder */
    })
}

/**
 * Process vendor node_modules TS with Babel.
 * The preset includes JSX, Flow, and some ESnext features.
 */
export const ruleVendorCompileTs = (berun: Berun, _) => {
  berun.webpack.module
    .rule('main')
    .oneOf('vendorcompilets')
    .test(/\.(jsx|ts|tsx)$/)
    .include.merge([berun.options.paths.metaWorkspace])
    .end()
    .use('babel')
    .loader(require.resolve('babel-loader'))
    .options({
      /* placeholder */
    })
}

/**
 * "file" loader makes sure those assets get served by WebpackDevServer.
 * When you `import` an asset, you get its (virtual) filename.
 * In production, they would get copied to the `build` folder.
 * This loader doesn't use a "test" so it will catch all modules
 * that fall through the other loaders.
 */
export const ruleMainStatic = (berun: Berun, _) => {
  berun.webpack.module
    .rule('main')
    .oneOf('static')
    // Exclude `js` files to keep "css" loader working as it injects
    // its runtime that would otherwise be processed through "file" loader.
    // Also exclude `html` and `json` extensions so they get processed
    // by webpacks internal loaders.
    .exclude.add(/\.(css|scss|sass|js|jsx|mjs|ts|tsx)$/)
    .add(/\.ejs$/)
    .add(/\.html$/)
    .add(/\.json$/)
    .add(/node_modules/)
    .end()
    .use('file')
    .loader(require.resolve('file-loader'))
    .options({
      name: 'static/media/[name].[hash:8].[ext]'
    })
}

export const ruleMainFonts = (berun: Berun, _) => {
  berun.webpack.module
    .rule('main')
    .oneOf('ttf')
    .test(/^.+\.(ttf)$/)
    .use('file')
    .loader(require.resolve('file-loader'))
    .options({
      name: 'static/fonts/[name].[hash:8].[ext]'
    })
}

export const ruleMainSvg = (berun: Berun, _) => {
  berun.webpack.module
    .rule('main')
    .oneOf('svg')
    .test(/\.svg$/)
    .exclude.add(/node_modules/)
    .end()
    .use('svgr')
    .loader(require.resolve('@svgr/webpack'))
    .end()
    .use('svgr')
    .loader(require.resolve('url-loader'))
}
