const { join } = require('path');
const { writeFileSync, mkdirSync, existsSync } = require('fs');
const rimraf = require('rimraf');
const serveStatic = require('serve-static');
const { resolve } = require('path');
const { portfinder, chalk, delay, createDebug, chokidar, signale, glob } = require('@umijs/utils');
const argv = require('./argv');
const setup = require('./middlewares/frontendMiddleware');
const pkg = require('../package.json');
const config = require('../config/config');
const mockMiddewares = require('./mock');
const emitter = require('./event');
const Server = require('./server');
const debug = createDebug('preset-build-in:proxy:createMiddleware');
// const proxyConfig = require('../config/proxy');
const loadDotEnv = require('./utils/loadDotEnv');
const { getSchema } = require('./openapi');
const cleanRequireCache = require('./utils/cleanRequireCache');


(async () => {
  const defaultPort = process.env.PORT || argv.port || (config && config.devServer && config.devServer.port);
  const port = await portfinder.getPortPromise({
    port: defaultPort ? parseInt(String(defaultPort), 10) : 8080,
  });
  const homename = process.env.HOST || (config && config.devServer && config.devServer.host) || '127.0.0.1';
  console.log(chalk.cyan('Starting the development server...'));
  // process.send && process.send({ type: 'UPDATE_PORT', port });
  const isHTTPS = process.env.HTTPS || (argv && argv.https);

  await delay(500);
  const absNodeModulesPath = `${process.cwd()}/node_modules`;
  const openAPIFilesPath = join(absNodeModulesPath, 'civ_open_api');

  const loadEnv = () => {
    const basePath = join(process.cwd(), '.env');
    const localPath = `${basePath}.local`;
    loadDotEnv(basePath);
    loadDotEnv(localPath);
  };

  loadEnv();

  // const absNodeModulesPath = cwd + '/node_modules';
  try {
    if (existsSync(openAPIFilesPath)) {
      rimraf.sync(openAPIFilesPath);
    }
    mkdirSync(join(openAPIFilesPath));
  } catch (error) {
    console.error(error);
  }

  const server = new Server({
    compress: true,
    https: !!isHTTPS,
    headers: {
      'access-control-allow-origin': '*',
    },
    port,
    beforeMiddlewares: [
      (config.mock || process.env.MOCK !== 'none') && mockMiddewares,
    ],
    afterMiddlewares: [serveStatic(openAPIFilesPath)],
    proxy: config.proxy,
    ...(config.devServer || {}),
  });


  setup(
    server.app,
    {
      outputPath: resolve(process.cwd(), pkg.name.toLocaleLowerCase()),
      publicPath: `/${pkg.name.toLocaleLowerCase()}`,
    },
    config,
    {
      port,
      homename,
    },
  );

  // proxy config 热更新
  const ignore = [
    // ignore mock files under node_modules
    'node_modules/**'
  ];

  const cwd = process.cwd();
  const proxyWatcherPaths = [
    ...(glob.sync('config/proxy.js', {
      cwd,
      ignore,
    }) || []),
    ...(glob.sync('**/proxy.js', {
      cwd,
      ignore,
    }) || []),
    ...(glob.sync('.env', {
      cwd,
      ignore,
    }) || []),
    ...(glob.sync('.env.local', {
      cwd,
      ignore,
    }) || [])
  ];


  const watcher = chokidar.watch(proxyWatcherPaths, {
    ignoreInitial: true,
  });
  const errors = [];

  watcher.on('ready', () => debug('Initial scan complete. Ready for changes')).on('all', async (event, file) => {
    debug(`[${event}] ${file}, reload proxy config`);``
    errors.splice(0, errors.length);
    cleanRequireCache(Array.from(new Set(proxyWatcherPaths)));
    if (!errors.length) {
      const hotProxy = require('../config/proxy');
      server.setupProxy && server.setupProxy(hotProxy[process.env.NODE_ENV], true);
      signale.success(`Proxy config parse success`);
    }
  });

  process.once('SIGINT', async () => {
    await watcher.close();
  });


  emitter.on('onDevCompileDone', async () => {
    try {
      const openAPIConfig = config.openAPI;
      if (openAPIConfig && openAPIConfig.schemaPath) {
        const openAPIJson = await getSchema(openAPIConfig.schemaPath);
        writeFileSync(
          join(openAPIFilesPath, 'civ-plugins_openapi.json'),
          JSON.stringify(openAPIJson, null, 2),
        );
      }
    } catch (error) {
      console.error(error);
    }
  });


  await server.listen({
    port,
    homename,
  });
})();