const environment = process.env.NODE_ENV || 'development'
const {routesByEnv, port} = require('./routes')
const routes = routesByEnv[environment]
const path = require('path')
const joinP = path.join.bind(null, __dirname)
const fs = require('fs')

const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const PeerDepsExternalsPlugin = require('peer-deps-externals-webpack-plugin')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')

const exclude = /node_modules/
const $ = {}

$.resolve = {
  extensions: ['.js', '.json', '.ts', '.tsx'],
  modules: [joinP('source'), joinP('node_modules')]
}

$.output = {
  publicPath: '/',
  path: joinP('lib'),
  filename: '[name].js',
  library: '[name]',
  libraryTarget: 'umd'
}

const bundleDefinitions = {
  'process.env': {
    NODE_ENV: JSON.stringify(environment)
  }
}

Object.keys(routes).forEach(key => {
  bundleDefinitions[key] = JSON.stringify(routes[key])
})

$.plugins = [
  new webpack.DefinePlugin(bundleDefinitions),
  new ForkTsCheckerWebpackPlugin({
    tsconfig: joinP('source/tsconfig.json')
  })
]

if (environment === 'development') {
  $.devtool = 'cheap-module-source-map'

  $.plugins.push(
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  )
}

if (environment === 'production') {
  $.plugins.unshift(
    new CleanWebpackPlugin($.output.path),
    new CleanWebpackPlugin('es')
  )

  $.plugins.push(
    new CopyWebpackPlugin([
      {from: 'package.json'}
    ]),
    new webpack.SourceMapDevToolPlugin({
      filename: '[file].map'
    }),
    new PeerDepsExternalsPlugin(),
    // new UglifyJsPlugin()
  )
}

$.module = {
  rules: [
    {
      enforce: 'pre',
      test: /\.js$/,
      loader: 'eslint-loader',
      exclude
    },
    {
      test: /\.js$/,
      exclude,
      use: [{loader: 'babel-loader'}]
    },
    {
      test: /\.tsx?$/,
      exclude,
      // include: path.resolve('source'),
      use: [
        // {loader: 'babel-loader'},
        {
          loader: 'ts-loader',
          options: {
            transpileOnly: true, // Type checking done via plugin.
            configFile: joinP('source/tsconfig.json')
            // compilerOptions: tsConfig.compilerOptions
          }
        }
      ]
    }
  ]
}

$.entry = {}

const hotReloadEntries = [
  `webpack-dev-server/client?http://0.0.0.0:${port}`,
  'webpack/hot/only-dev-server'
]

const moduleIndexFilename = 'index'

fs.readdirSync(joinP('source/pages')).forEach(filename => {
  const entryName = path.join('pages', filename, moduleIndexFilename.replace(/\.tsx?$/, ''))
  let modules = [joinP('source/pages', filename, moduleIndexFilename)]

  if (environment === 'development') {
    modules = [...hotReloadEntries, ...modules]
  }

  $.entry[entryName] = modules

  $.plugins.push(new HtmlWebpackPlugin({
    title: 'Cloudflare Apps Components',
    chunks: [entryName],
    filename: `pages/${filename}/index.html`,
    template: joinP('source/pages', filename, 'index.ejs')
  }))
})

function recursiveEntrySearch (directoryPath) {
  fs.readdirSync(joinP('source', directoryPath)).forEach(filename => {
    const relativeFilePath = path.join(directoryPath, filename)
    const fullFilePath = joinP('source', relativeFilePath)

    if (fs.lstatSync(fullFilePath).isDirectory()) {
      recursiveEntrySearch(relativeFilePath)
    } else if (/index/.test(filename)) {
      // Note: Webpack automatically appends .js to all entries.
      const entryName = relativeFilePath
        .replace(/\.[a-zA-Z]*$/, '')

      $.entry[entryName] = fullFilePath
    }
  })
}

recursiveEntrySearch('components')

module.exports = $
