'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');

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

// FETCH ARGS
const { remotesImport } = tools.getArgs();

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

  return Promise.resolve()
    .then(() => {
      return metadataUtils.appEnvs.getMetadata(prj);
    })
    .then((envsMetadata) => {
      let hasPreprod = true;

      if (prj.hostName && prj.hostName === 'sedia') {
        hasPreprod = false;
      }

      return innerCompositeCore.getCompositeDeps(
        prj.folder,
        envsMetadata,
        envTarget,
        prj.standalone,
        hasPreprod
      );
    })

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

const getLocalProjectDeps = (prj, snapshotsMetadata) => {
  tools.logInfo(`Getting deps for ${prj.name}`);

  // check dependencies file - default
  const prjJsonFile = path.join(process.cwd(), prj.folder, 'dependencies-base.json');
  const prjDeps = tools.getJsonFileContent(prjJsonFile) || {};

  // check dependencies composite file - default
  const prjCompJsonFile = path.join(process.cwd(), prj.folder, 'dependencies-composite.json');

  const depsJson = tools.getJsonFileContent(prjCompJsonFile);
  let prjCompDeps;
  if (depsJson.dependencies) {
    prjCompDeps = depsJson.dependencies || {};
  } else {
    prjCompDeps = depsJson || {};
  }

  return { ...prjDeps, ...prjCompDeps };
};

module.exports.getLocalProjectsDeps = () => {
  tools.logTitle('Getting project dependencies');

  const projects = configUtils.projects.getProjects();
  let deps = {};

  projects.forEach((p) => {
    if (p) {
      const prjDeps = getLocalProjectDeps(p);
      deps = { ...deps, ...prjDeps };
    }
  });

  return deps;
};

const getLocalProjectFixedDeps = (module.exports.getLocalProjectFixedDeps = (prj) => {
  tools.logTitle('Getting project fixed dependencies - not part of the composite');

  return Promise.resolve()
    .then(() => {
      let deps = {};

      if (prj.fixedDependencies) {
        tools.logInfo('Project fixed dependencies found...processing');
        console.log(prj.fixedDependencies);

        prj.fixedDependencies.forEach((dep) => {
          const pkg = configUtils.packages.getPackageByNpmPkg(dep, true);
          const newDep = { [dep]: metadataUtils.packageUtils.getPackageVersionLast(pkg) };
          deps = { ...deps, ...newDep };
        });
      }

      tools.logInfo('Project fixed dependencies remapped : ');
      console.log(deps);

      return deps;
    })

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

module.exports.getLocalProjectsFixedDeps = async (_) => {
  const projects = configUtils.projects.getProjects();
  let deps = {};

  const promises = projects.map(async (prj) => {
    const prjDeps = await getLocalProjectFixedDeps(prj);
    deps = { ...deps, ...prjDeps };
    return deps;
  });

  await Promise.all(promises);
  return deps;
};

module.exports.installDeps = (prj, envTarget) => {
  tools.logInfo('install.projects.installDeps');

  let finalDeps, compositeDeps;

  return Promise.resolve()
    .then(() => {
      return getDeps(prj, envTarget);
    })
    .then((deps) => {
      // storing compositeDeps
      compositeDeps = deps;
    })

    .then(() => {
      return getLocalProjectFixedDeps(prj);
    })

    .then((prjFixedDeps) => {
      // storing for archiving
      finalDeps = { ...compositeDeps, ...prjFixedDeps };

      // fetching extra dependencies on project
      const prjBaseJsonFile = path.join(process.cwd(), prj.folder, 'dependencies-base.json');

      tools.logInfo(`Getting base dependencies from : ${prjBaseJsonFile}`);
      console.log(tools.getJsonFileContent(prjBaseJsonFile));

      const prjBaseDeps = tools.getJsonFileContent(prjBaseJsonFile) || {};

      tools.logInfo('Found base dependencies:');
      console.log(prjBaseDeps);

      const fixedDeps = configUtils.global.getConfigOptions().NPM_FIXED_DEPENDENCIES;

      return innerCommon.installDeps({ ...prjBaseDeps, ...compositeDeps, ...prjFixedDeps, ...fixedDeps });
    })

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

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

module.exports.installDepsStandalone = (prj) => {
  return Promise.resolve()
    .then(() => {
      return innerCommon.executeInstall(prj.paths.installPath);
    })

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

const getLocalProjectRemoteDeps = (module.exports.getLocalProjectRemoteDeps = (prj) => {
  if (prj.initRemoteDependencies && remotesImport) {
    tools.logTitle(`Detecting remotes deps for project : ${prj.name}`);

    const euiVersion = configUtils.global.getLocalEuiVersion();
    const remotes = configUtils.remotes.getCsdrRemotesArray(prj.hostName, euiVersion);

    let remoteDeps = {};
    remotes
      .map((r) => configUtils.remotes.getRemote(r.name))
      .map((r) => {
        return { npmgPkg: r.npmPkg, version: metadataUtils.packageUtils.getPackageVersionLast(r) };
      })
      .forEach((r) => {
        if (!r.version) {
          tools.logInfo(`${r.npmgPkg} => no version found, probably the remote hasn't been released yet...skipping`);
        } else {
          remoteDeps[r.npmgPkg] = r.version;
        }
      });

    return remoteDeps;
  }
});

module.exports.getLocalProjectsRemoteDeps = async (_) => {
  const projects = configUtils.projects.getProjects();
  let deps = {};

  const promises = projects.map(async (prj) => {
    const prjDeps = await getLocalProjectRemoteDeps(prj);
    deps = { ...deps, ...prjDeps };
    return deps;
  });

  await Promise.all(promises);
  return deps;
};

module.exports.importLocalProjectRemotes = (prj, remoteDeps) => {
  if (prj.initRemoteDependencies) {
    tools.logInfo(`Import remotes for project : ${prj.name}`);

    remoteDeps = Object.keys(remoteDeps);

    if (remoteDeps.length === 0) {
      tools.logWarning('Remotes dependencies not found for project...skipping');
    } else {
      tools.logInfo(`Initializing ${remoteDeps.length} remotes`);

      remoteDeps.forEach((remoteNpmPkg) => {
        tools.logInfo(`\nChecking import for : ${remoteNpmPkg}`);

        // check if package has been installed locally
        if (configUtils.remotes.isLocalRemote(remoteNpmPkg)) {
          tools.logInfo('remote is installed locally...skipping import');
        } else {
          const remote = configUtils.remotes.getRemoteByNpmPkg(remoteNpmPkg, true);
          const projectElementsPath = path.join(process.cwd(), prj.folder, 'src', 'assets', 'elements', remote.name, 'bundles');

          const npmPkgScope = remoteNpmPkg.substr(0, remoteNpmPkg.indexOf('/'));
          const npmPkgName = remoteNpmPkg.substr(remoteNpmPkg.indexOf('/') + 1);
          const remoteNmPath = path.join(process.cwd(), 'node_modules', npmPkgScope, npmPkgName, 'bundles');

          tools.logInfo(`${remoteNpmPkg} - injecting in ${projectElementsPath}`);
          tools.copydir(remoteNmPath, projectElementsPath);
        }
      });
    }
  }
};

module.exports.importLocalProjectsRemotes = (deps) => {
  const projects = configUtils.projects.getProjects();

  tools.logTitle('Importing local projects remotes');

  if (remotesImport) {
    projects.forEach((p) => {
      if (p) {
        this.importLocalProjectRemotes(p, deps);
      }
    });
  }
};
