const esbuild = require('esbuild');
const resolve = require('esbuild-plugin-resolve');
const fs = require('fs-extra');
const { exec } = require('child_process');
const babel = require('./esbuild-plugin-babel');
const path = require('path')

const BUILD_DIR = './web-build';

class EsBuilder {
  cleanBuildDir() {
    if (fs.existsSync(BUILD_DIR)) {
      fs.removeSync(BUILD_DIR);
    }
  }

  prepareIndexHtml() {
    console.log('build success');
    try {
    const bundleName = fs.readdirSync('./web-build').find(n => /^bundle.*js$/.test(n));
    let content = fs.readFileSync(__dirname + '/index.html', 'utf-8');
    content = content.replace(/".\/bundle.js"/, `"./${bundleName}"`);
    fs.writeFileSync('./web-build/index.html', content);
    } catch (err) {
      console.error(err);
    }
  }

  patchPackageLib(paths) {
    paths.forEach((path) => {
      const packageFile = `${__dirname}/../node_modules/${path}/package.json`;
      if (fs.existsSync(packageFile)) {
        const _package = fs.readJSONSync(packageFile);
        console.log('patch applied on package at.. ', packageFile);
        delete _package['module'];
        fs.writeFileSync(packageFile, JSON.stringify(_package, null, 4));
      }
    });
  }

  patchWithDevTools(path) {
    const packageFile = `${__dirname}/../node_modules/${path}`;
    if (fs.existsSync(packageFile)) {
      const _package = "import * as React from 'react';export function withDevTools(AppRootComponent) {return (props) => React.createElement(AppRootComponent, { ...props });}"
      fs.writeFileSync(packageFile, _package);
    }
  }

  buildLibraries() {
    const promises = [{
      name: 'expo-web-browser',
      build: (path) => {
        fs.writeFileSync(`${path}/build/WebBrowser.js`, `
        export const openBrowserAsync = (url) => {
          window.open(url, '_blank');
        };`);
      }
    }].map(p => {
      let libPath = `${__dirname}/../node_modules/${p.name}`;
      if (!fs.existsSync(libPath)) {
        libPath = `${__dirname}/../node_modules/@wavemaker/app-rn-runtime/node_modules/${p.name}`;
      }
      if (!fs.existsSync(libPath)) {
        const msg = `${p.name} library is not found`;
        console.error(msg);
        return Promise.reject(msg);
      }
      const destPath = `${__dirname}/node_modules/${p.name}`;
      if (fs.existsSync(destPath)) {
        fs.removeSync(destPath);
      }
      fs.copySync(libPath, destPath);
      return p.build && p.build(destPath);
    });
    return Promise.all(promises)
        .then(() => this.patchPackageLib(['@koale/useworker', 'victory']))
        .then(() => this.patchWithDevTools('expo/build/launch/withDevTools.js'))
        .then(() => {
          console.log('*********** LIBRARIES ARE BUILT FOR ESBUILD **************');
        }, (e) => {
          console.error(e);
          console.log('*********** FAILED TO BUILD LIBRARIES FOR ESBUILD **************');
        });
  }

  build() {
    console.log('excluded react-native-vector-icons module in esbuild');
    return esbuild.build({
      entryPoints: ['./node_modules/expo/AppEntry.js'],
      external:['./node_modules/react-native-vector-icons'],
      bundle: true,
      entryNames: 'bundle-[hash]',
      outdir: 'web-build',
      tsconfig: './esbuild/jsconfig.json',
      define: {'process.env.NODE_ENV': '"development"', '__DEV__': false, global:'window'},
      resolveExtensions: ['.web.tsx','.web.ts','.web.jsx','.web.js','.tsx','.ts','.jsx','.js',],
      loader: {".png": "file", ".ttf": "file", ".js": "jsx", ".gif": "file", ".svg": "file" },
      minify: false,
      sourcemap: true,
      plugins: [babel({
        filter: /\/src\/.*jsx?/,
        config : {
          targets: {
            browsers: 'last 2 versions',
            esmodules: true
          },
          sourceMaps: 'inline',
          plugins: [__dirname + '/../scripts/wm-babel.transform.plugin.js']
        }
      }), resolve({
        'victory-native': 'victory'
      })]
    })
  }

  triggerBuild() {
    console.log('*********** REACT NATIVE ESBUILD STARTED **************');
    console.time('react native with esbuild');
    this.cleanBuildDir();
    this.build()
    .then(() => this.prepareIndexHtml())
    .then(() => {
      console.timeEnd('react native with esbuild');
      console.log('*********** REACT NATIVE ESBUILD SUCCESSFUL **************');
    }).catch(() => {
      console.timeEnd('react native with esbuild');
      console.log('*********** REACT PROJECT ESBUILD FAILED **************');
    });
  }
}

if (process.argv[2] === '--prepare-lib') {
  (new EsBuilder()).buildLibraries();
} else {
  (new EsBuilder()).triggerBuild();
}
