const nextPort = 5010
const proxyPort = nextPort - 10
const {globSync} = require('glob')
const fs = require('fs')
const express = require('express')
const next = require('next')
const helmet = require('helmet')
const noCache = require('nocache')
const httpProxy = require('express-http-proxy');
const proxy = require('http-proxy-middleware');
const routes = require('./routes')
const { join, resolve } = require('path')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = routes.getRequestHandler(app)
const buildEnv = process.env.DEPLOY_ENV || 'dev'
const { assetPrefix, $assets } = require(`./next.${buildEnv}.config`)
const spawn = require('cross-spawn')
const chalk = require('chalk')
const xmpieBuild = fs.existsSync('./.xmpie')
const fetch = require('node-fetch')

const { getLocalWidgetsConfig, getWidgetsConfiguration, getLocalDevWidgetIds, getWidgetsConfig } = require('./widgetsProxyHelpers.js')

require('./ustore-internal/scripts/applyFeaturesConfig')

const argv = (str) => {
  const idx = process.argv.findIndex((a) => a.startsWith(str))
  if (idx > -1) {
    return process.argv[idx].substring(str.length + 1)
  }
  return null
}

const ducBuild = argv('ducbuild')
const ducsPath = ducBuild && resolve(ducBuild === '1' ? '../ustore-ducs' : ducBuild)

const ducsConfig = {
  root: ducsPath,
  dist_dev: ducBuild && join(ducsPath, 'dist_dev')
}

const widgetbuild = argv('widgetbuild')
const widgetsPath = widgetbuild && resolve(widgetbuild === '1' ? '../widgets' : widgetbuild)

const widgetsConfig = {
    root: widgetsPath,
    dist_dev: widgetbuild && join(widgetsPath, 'build')
}

const uStoreServerUrl = argv('server') || 'http://uStoreNG.xmpie.net' // 'http://frontend1'

const proxyDirectories = ['/ustore', '/uStore', '/uStoreRestAPI', '/uStoreThemeCustomizations', '/uStoreThemes', '/favicon.ico']

const getDucs = async () => {
  const res = await fetch(`${uStoreServerUrl.startsWith('http') ? '' : 'http://'}${uStoreServerUrl}/uStoreRestAPI/v1/system/properties/form/widgets`)
  return res.text()
}

const makeHttpProxy = (base) => httpProxy(`${uStoreServerUrl}`,
  {
    https: false,
    proxyReqPathResolver: (req) => base + req.url,
  }
)

// Spins a process for compiling the DUC project.
if (ducBuild) {
  console.log(chalk.green('Start DUC build process'))
  spawn('npm', ['--prefix', ducsConfig.root, 'start'], { stdio: 'inherit' })
}

// Spins a process for compiling the Widgets project.
if (widgetbuild) {
    console.log(chalk.green('Start Widgets build process'))
    const npm = spawn('npm run', ['--prefix', widgetsConfig.root, 'start:dev'], { env: process.env, PATH: process.env.PATH })
    npm.stdout.on('data', (data) => {
        console.log(data.toString())
    })
    npm.stderr.on('data', (data) => {
        if (`${data}`.startsWith('[BABEL] Note: ')) {
            console.log(chalk.gray(data))
        } else {
            console.log(chalk.red(data))
        }
    });
    ['beforeExit', 'exit'].forEach(eventName => process.on(eventName, () => npm.kill(-9)))
}

// Allows running the client only version under the out directory
// This is to enable testing the client only build.
if (argv('client')) {
  console.log('\x1b[31m%s\x1b[0m', '=====! Using exported directory !=====');
  const proxyServer = express();

  // create a proxy that will redirect all assets request to the out directory
  proxyServer.use(
    '/',
    proxy({
      target: `http://localhost:${nextPort}`,
      pathRewrite: {
        [`^${assetPrefix}`]: '/'
      }
    })
  );


  proxyServer.listen(proxyPort, proxyError => {
    if (proxyError) throw proxyError;

    const nextServer = express()

    nextServer.use(noCache())
    nextServer.use(helmet.frameguard())

    //serve static files from the out directory
    if (dev) {
      nextServer.use(express.static(__dirname + '/out'))
      nextServer.use('/webcomponents', express.static(join(__dirname, './webcomponents')))
      nextServer.use('/ducs', express.static(join(__dirname, './ducs')))

      proxyDirectories.forEach(p => nextServer.use(p, makeHttpProxy(p)))
    }
    // all requests to the server should respond with the index.html
    // this enabled the client sides routing
    nextServer.get('*', (req, res) => {
      res.sendFile(__dirname + '/out/index.html')
    })


    nextServer.listen(nextPort, (err) => {
      if (err) throw err
      console.log(`next > Ready on http://localhost:${proxyPort}`)
    })
  });
} else {
  // This is the normal development server of nextjs
  const proxyServer = express();

  // Create a proxy server with url rewrite for the asset prefix
  proxyServer.use(
    '/',
    proxy({
      target: `http://localhost:${nextPort}`,
      pathRewrite: {
        [`^${assetPrefix}`]: '/'
      }
    })
  );

  proxyServer.listen(proxyPort, proxyError => {
    if (proxyError) throw proxyError;

    app.prepare()
      .then(() => {
        const nextServer = express()

        // set the asset prefix for the nextjs application
        app.setAssetPrefix(`http://localhost:${proxyPort}${assetPrefix}`);

        nextServer.use(noCache())
        nextServer.use(helmet.frameguard())

        // serve  static assets from global directories and directories inside the theme.
        if (dev) {
          console.log('Dev server is serving static files')
          nextServer.use(`/assets`, express.static($assets))
          nextServer.use('/static', express.static(join(__dirname, '/static')))
          nextServer.use('/static-internal', express.static(join(__dirname, '/ustore-internal/static')))
          nextServer.use('webcomponents', express.static(join(__dirname, './webcomponents')))
          if (ducBuild) {
            nextServer.use('/ducs', express.static(ducsConfig.dist_dev))
            nextServer.use('/uStoreRestAPI/v1/system/properties/form/widgets', async (req, res, next) => {
              const dirs = fs.readdirSync(ducsConfig.dist_dev)
              const ducs = dirs.filter(dir => dir !== 'Sample' || !xmpieBuild).map(dir => ({name: dir, baseUrl: `/ducs/${dir}`}))
              if (xmpieBuild) {
                res.send(`var xmpie_uStore_DUCs = ${JSON.stringify(ducs)}`)
              } else {
                const widgetScript = await getDucs()
                res.send(`${widgetScript}; xmpie_uStore_DUCs = [...xmpie_uStore_DUCs, ...${JSON.stringify(ducs)}];`)
              }
            })
          }
          if (widgetbuild) {
            try {
                const localWidgetsDirs = globSync('**/config.json', { cwd: widgetsConfig.dist_dev })
                const localWidgetsList = localWidgetsDirs.map(dir => dir.replace('\\config.json', ''))
                const localWidgetsIds = getLocalDevWidgetIds(localWidgetsList)
                nextServer.use('/widgets', express.static(join(widgetsConfig.dist_dev, 'dist_dev')))
                nextServer.use('/uStoreThemeCustomizations/:id/Published/Widgets/widgetConfig.js', async (req, res) => {
                    const localWidgetsConfig = getLocalWidgetsConfig(localWidgetsDirs)
                    const widgetsConfigurations = await getWidgetsConfiguration(uStoreServerUrl, req.params.id)
                    const window = {}
                    // eslint-disable-next-line no-eval
                    eval(widgetsConfigurations)
                    localWidgetsIds.forEach((widgetId, widgetName) => {
                        const localWidgetConfig = localWidgetsConfig.find(widget => widget.uniqueIdentifier === widgetName) || ''
                        const buff = Buffer.from(localWidgetConfig.defaultConfiguration, 'utf-8');
                        window.uStoreWidgetsConfiguration[widgetId] = buff.toString('base64')
                    })
                    let config = 'window.uStoreWidgetsConfiguration = window.uStoreWidgetsConfiguration || {};'
                    Object.entries(window.uStoreWidgetsConfiguration).forEach(([key, value]) => {
                        config += `window.uStoreWidgetsConfiguration['${key}'] = '${value}';`
                    });
                    res.set('Content-Type', 'application/x-javascript')
                    res.send(config)
                })
                nextServer.use('/uStoreRestAPI/v1/store/resourceByUrl', async (req, res, next) => {
                    // Request for resource type 6 is the request for widgets config.
                    if (req.query.type === '6') {
                        const { configurationUrl, definitions, instances } = await getWidgetsConfig(argv, uStoreServerUrl, localWidgetsDirs, localWidgetsList, localWidgetsIds, req.query.url, req.query.cultureCode)
                        res.set('Content-Type', 'application/x-javascript')
                        res.send(`var xmpie_uStore_widgets = { configurationUrl: '${configurationUrl}', definitions: ${JSON.stringify(definitions)}, instances: ${JSON.stringify(instances)} }`)
                    } else {
                        next()
                    }
                })
            } catch (e) {
                console.log(chalk.red(e))
            }
          }
          proxyDirectories.forEach(p => nextServer.use(p, makeHttpProxy(p)))
        }

        // all requests are processed by the next application
        nextServer.get('*', (req, res) => {
          return handle(req, res)
        })

        nextServer.listen(nextPort, (err) => {
          if (err) throw err
          console.log(`next > Ready on http://localhost:${proxyPort}`)
        })
      })
      .catch((ex) => {
        console.error(ex.stack)
        process.exit(1)
      })
  })
}
