'use strict';

// GLOBAL
const path = require('path');

// LOCAL
const tools = require('../../utils/tools');
const configUtils = require('../config/config-utils');
const metadataUtils = require('../metadata/metadata-utils');
const initUtils = require('../init/init-utils');

// INNER MODULES
const innerCommon = require('./common');
const innerCompositeCore = require('./composite-core');

// FETCH ARGS
const { dryRun, skipRemotes } = tools.getArgs();


const allPkgInstall = (envTarget) => {
  return Promise.resolve()

    // getting packages to be remotely installed
    .then(() => {
      tools.logInfo('Getting remote installable packages');

      // filter on packages who are considered remote and for which dependencies have been found
      const packages = configUtils.packages.getRemotePackages().filter((p) => {
        return p.paths.remoteNodeModules;
      });

      // adding new "remotes" type for new stand-alone remote config
      let remotes = [];
      if (!skipRemotes) {
        remotes = configUtils.remotes.getRemotes();
      }

      return [...packages, ...remotes];
    })

    // iterate on all packages found earlier
    .then((packages) => Promise.resolve().then(() => {
      return packages.reduce((promise, pkg) => {
        return promise.then(() => (
          pkgInstall(pkg, envTarget)
        ));
      }, Promise.resolve());
    }))

    .catch((e) => {
      throw(e)
    });
}

const pkgInstall = (pkg, envTarget) => {
  tools.logTitle(`Processing installation for : ${pkg.name}`);

  let finalDeps;

  return Promise.resolve()
    .then(() => {
      // fetching deps from dependencies base and composite if any
      return getDeps(pkg, envTarget);
    })
    .then((compositeDeps) => {
      // storing for later exports
      finalDeps = compositeDeps;

      // getting base deps (3rd parties)
      let baseDeps = {}, deps;

      const depsBaseJsonFile = path.join(pkg.paths.root, 'dependencies-base.json');
      if (tools.isFileExists(depsBaseJsonFile)) {
        baseDeps = tools.getJsonFileContent(depsBaseJsonFile);
      }

      // merging base+composite
      deps = { ...baseDeps, ...compositeDeps };


      // parse eUI deps and explode the sub-packages (v17 issues)
      // getting package eUI version
      const euiVersion = configUtils.packages.getPackageEuiVersion(pkg);

      // add sub-eUI packages for v17
      if (euiVersion === '17.x') {
        Object.keys(deps).forEach((dep) => {
          if (dep === '@eui/deps-base') {
            deps['@eui/components'] = deps[dep];
            deps['@eui/showcase'] = deps[dep];
          }
        });
      }

      // updating package json file before installation
      const pkgJsonFile = path.resolve(pkg.paths.root, 'package.json');
      const pkgJson = require(pkgJsonFile);

      pkgJson.dependencies = deps;

      // store dependencies metadata for later fetch of remote deps installed for a particular version published
      pkgJson.remoteDependencies = deps;

      // checking for resolution updates according to eUI version used
      initUtils.global.initRemoteFilesAndResolutions(pkg.paths.root, euiVersion);


      if (dryRun) {
        tools.logInfo('DRY-RUN - skipping install');

      } else {
        // Updating file and installing
        if (Object.keys(pkgJson.dependencies).length !== 0) {
          tools.writeJsonFileSync(pkgJsonFile, pkgJson);

          tools.logInfo('installing dependencies');
          console.log(pkgJson.dependencies);

          if (pkg.standalone) {
            return innerCommon.executeInstall(pkg.paths.root, configUtils.global.getConfigOptionsStandalone().NPM_REGISTRY_INSTALL);
          } else {
            return innerCommon.executeInstall(pkg.paths.root);
          }


        } else {
          tools.logWarning('No dependencies found to install');
        }
      }
    })

    .then(() => {
      // returning only the composite deps found, only those will be stored in the metadata
      return finalDeps;
    })

    .catch((e) => {
      throw(e)
    })

    // reseting package.json
    .finally(() => {
      if (!dryRun) {
        const pkgJsonFile = path.resolve(pkg.paths.root, 'package.json');
        const pkgJson = require(pkgJsonFile);

        pkgJson.dependencies = {};

        tools.writeJsonFileSync(pkgJsonFile, pkgJson);
      }
      return finalDeps;
    });
}


const getDeps = module.exports.getDeps = (pkg, envTarget) => {
  tools.logInfo('install.remotes.getDeps');

  return Promise.resolve()
    .then(() => {
      return metadataUtils.remotePackage.getMetadataEnvs(pkg);
    })
    .then((envsMetadata) => {

      let hasPreprod = true;

      if (pkg.build && pkg.build.appTarget && (pkg.build.appTarget === 'SEDIA_ONLY' || pkg.build.appTarget === 'MWP_SEDIA')) {
        hasPreprod = false;
      }

      return innerCompositeCore.getCompositeDeps(
        pkg.paths.fromRoot,
        envsMetadata,
        envTarget,
        pkg.standalone,
        hasPreprod
      );
    })

    .catch((e) => {
      throw e;
    })
}


module.exports.installDeps = (pkg, envTarget) => {
  tools.logTitle('Remote dependencies installation');

  return Promise.resolve()
    .then(() => {
      if (pkg) {
        return pkgInstall(pkg, envTarget);
      } else {
        return allPkgInstall(envTarget);
      }
    })

    .catch((e) => {
      throw e;
    })
  }
