'use strict';

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

// LOCAL
const tools = require('../../utils/tools');
const metadataUtils = require('../metadata/metadata-utils');

// INNER MODULES
const innerCommon = require('./common');




const getDeps_DEV = (compositeDeps, standalone = false) => {
  return Promise.resolve()
    .then(() => {
      if (standalone) {
        return innerCommon.getResolvedCarretDepsStandalone(compositeDeps, false, true);
      } else {
        return innerCommon.getResolvedCarretDeps(compositeDeps, false, true);
      }
    })

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



const getDeps_TST = (compositeDeps, standalone = false) => {
  return Promise.resolve()
    // Re-mapping the dependencies found against their max "carret" versions found in the base dependencies defs in the project
    .then(() => {
      if (standalone) {
        return innerCommon.getResolvedCarretDepsStandalone(compositeDeps, true, false);
      } else {
        return innerCommon.getResolvedCarretDeps(compositeDeps, true, false);
      }
    })

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




const getCompositeDepsByEnv = (compositePath, envTarget, envsMetadata, prevEnv, currentEnv) => {

  let prevEnvDeps = {}, currentEnvDeps = {};

  if (envsMetadata[prevEnv]) {
    prevEnvDeps = envsMetadata[prevEnv].dependencies;
  } else {
    throw new Error(`
      ${prevEnv} dependencies not found for ${currentEnv} dependencies fetch, ensure that the project/remote has been delivered to a previous environment first
    `);
  }

  if (envsMetadata[currentEnv]) {
    currentEnvDeps = envsMetadata[currentEnv].dependencies;
  }


  // if default composite type then we iterate over all detected composite files by env
  let depsToResolve = false;

  return Promise.resolve()
  .then(() => {
    tools.logTitle('Processing accumulated composites for ALL composite types');
    const filesByEnv = tools.getFiles(compositePath).filter(f => f.startsWith(`dependencies-composite-${envTarget}` ));
    var returnedDeps = {};

    filesByEnv.forEach((f) => {
      tools.logInfo(`Parsing : ${f}`);
      const compositeFile = path.join(process.cwd(), compositePath, f);
      const fileDeps = tools.getJsonFileContent(compositeFile);
      const deps = fileDeps.lockedDependencies || fileDeps.forcedCarretDependencies || {};
      console.log(JSON.stringify(deps, null, 2));
      returnedDeps = { ...returnedDeps, ...deps};
      if (fileDeps.forcedCarretDependencies) {
        depsToResolve = true;
      }
    });

    return { ...prevEnvDeps, ...returnedDeps };
  })

  .then((deps) => {
    if (depsToResolve) {
      tools.logInfo('Resolving forced dependencies for env');
      return innerCommon.getResolvedCarretDeps(deps, true, false);
    } else {
      return deps;
    }
  })

  .then((deps) => {
    tools.logInfo('Scanning resulting deps for RC detection (do avoid RC spreading up to non DEV envs)');
    const depsToScan = Object.keys(deps);
    depsToScan.forEach((d) => {
      if (deps[d].indexOf('-rc.') > -1) {
        tools.logInfo(`RC deps found : ${deps[d]}`);
        tools.logWarning('In order to prevent this, your RC next/ branch should be released to develop/master branch of the package, support/ branch created for supporting older version in upper environments')
        throw new Error('NOT_ALLOWED_RC_DEPS_FOR_NON_DEV_ENVIRONMENT_FOUND');
      }
    })
    return deps;
  })
  .catch((e) => {
    throw e;
  })

}








module.exports.getCompositeDeps = (
  compositePath,
  envsMetadata,
  envTarget = 'DEV',
  standalone = false,
  hasPreprod = true
) => {

  tools.logInfo('install.compositeCore.getCompositeDeps');
  tools.logInfo(`Processing installation at : ${compositePath} for env: ${envTarget}`);

  return Promise.resolve()
    // getting root composite - dependencies-composite.json content
    .then(() => {
      const compositeJsonFile = path.join(process.cwd(), compositePath, 'dependencies-composite.json');
      const compositeDeps = tools.getJsonFileContent(compositeJsonFile) || {};

      if (compositeDeps.dependencies) {
        return compositeDeps.dependencies;
      } else {
        return compositeDeps;
      }
    })

    // getting env specific composite
    .then((compositeDeps) => {
      /**
      * For DEV target, we take the outermost known versions of the packages,
      * including : SNAPSHOTS & LATEST
      */
      if (envTarget === 'DEV') {
        return getDeps_DEV(compositeDeps, standalone);
      }


      /**
      * For TST target, we take only the LATEST know versions of the packages,
      * including : LATEST
      */
      if (envTarget === 'TST') {
        return getDeps_TST(compositeDeps, standalone);
      }


      /**
      * For INT target, the base versions of packages is
      * Default : dependencies of LATEST TST known composite
      * overridden by : INT composite - locked dependencies to declare the deps that are staying on the TST env and
      * will not go further for the moment.
      */
      if (envTarget === 'INT') {
        return getCompositeDepsByEnv(
          compositePath,
          envTarget,
          envsMetadata,
          'TST', 'INT'
        );
      }


     /**
      * For ACC, the base versions of packages is
      * Default : dependencies of LATEST INT known composite
      * overridden by : lockedDependencies if any
      */
      if (envTarget === 'ACC') {
        return getCompositeDepsByEnv(
          compositePath,
          envTarget,
          envsMetadata,
          'INT', 'ACC'
        );
      }


     /**
      * For PROD target, the base versions of packages is
      * Default : PROD respective composite
      */
      if (envTarget === 'PROD') {
        if (hasPreprod) {
          return getCompositeDepsByEnv(
            compositePath,
            envTarget,
            envsMetadata,
            'PPD', 'PROD'
          );
        } else {
          return getCompositeDepsByEnv(
            compositePath,
            envTarget,
            envsMetadata,
            'TRN', 'PROD'
          );
        }
      }


     /**
      * For TRN, the base versions of packages is
      * Default : dependencies of LATEST ACC known composite
      * overridden by : hotfixDependencies if any
      */
      if (envTarget === 'TRN') {
        if (hasPreprod) {
          return getCompositeDepsByEnv(
            compositePath,
            envTarget,
            envsMetadata,
            'PROD', 'TRN'
          );
        } else {
          return getCompositeDepsByEnv(
            compositePath,
            envTarget,
            envsMetadata,
            'ACC', 'TRN'
          );
        }
      }

      /**
      * For PPD, the base versions of packages is
      * Default : dependencies of LATEST ACC known composite
      * overridden by : hotfixDependencies if any
      */
      if (envTarget === 'PPD') {
        return getCompositeDepsByEnv(
          compositePath,
          envTarget,
          envsMetadata,
          'ACC', 'PPD'
        );
      }


      /**
      * For DLT, the base versions of packages is
      * Default : dependencies of LATEST ACC known composite
      */
      if (envTarget === 'DLT') {
        return getCompositeDepsByEnv(
          compositePath,
          envTarget,
          envsMetadata,
          'ACC', 'DLT'
        );
      }
    })

    // Finally the re-mapped env-based composite of dependencies is returned
    .then((finalDeps) => {
      tools.logInfo('Packages composite found for target : ');
      console.log(finalDeps);

      // returning the composite packages found
      return finalDeps;
    })

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

