'use strict';

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

// 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 innerProjects = require('./projects');

// FETCH ARGS
const { skipLocalPackagesDeps, skipInstall } = tools.getArgs();




const getLocalPackageDeps = (pkg) => {
  let pkgJsonFile;

  if (pkg.parent) {
    return {};
  } else {
    if (pkg.child) {
      pkgJsonFile = path.join(process.cwd(), 'packages', pkg.parentPkg, 'packages', pkg.folder || pkg.name, 'package.json');
    } else {
      pkgJsonFile = path.join(process.cwd(), 'packages', pkg.name, 'package.json');
    }
  }

  return tools.getJsonFileContent(pkgJsonFile).dependencies || {};
}


const getLocalPackagesDeps = module.exports.getLocalPackagesDeps = () => {
  let packages = configUtils.packages.getPackages();
  let deps = {};

  packages = packages.filter(p => !p.skipDependencies);

  packages.forEach(p => {
    const pkgDeps = getLocalPackageDeps(p);

    tools.logInfo(`Getting local dependencies for ${p.name}`);
    console.log(JSON.stringify(pkgDeps, null, 2));

    const pdeps = Object.keys(pkgDeps)
      .reduce((acc, k) => {
        if (k.indexOf('@eui') !== -1 ) {
          if (k.indexOf('@eui/ecl') !== -1 ||
              k.indexOf('@eui/styles-base') !== -1 ||
              k.indexOf('@eui/styles') !== -1
          ) {
            acc[k] = pkgDeps[k];
          }
        } else {
          acc[k] = pkgDeps[k];
        }
        return acc;
      }, {});

    deps = { ...deps, ...pdeps };
  })

  return deps;
}


const getLocalPackageCompositeDeps = (pkg) => {
  let pkgJsonFile;

  if (!skipLocalPackagesDeps) {

    if (pkg.standalone) {
      pkgJsonFile = path.join(process.cwd(), 'dependencies-composite.json');
    } else {
      if (pkg.child) {
        pkgJsonFile = path.join(process.cwd(), 'packages', pkg.parentPkg, 'packages', pkg.folder || pkg.name, 'dependencies-composite.json');
      } else {
        pkgJsonFile = path.join(process.cwd(), 'packages', pkg.name, 'dependencies-composite.json');
      }
    }

    if (tools.isFileExists(pkgJsonFile)) {
      tools.logInfo(`found ${pkgJsonFile}, parsing...`);
    }

    return tools.getJsonFileContent(pkgJsonFile) || {};

  } else {
    tools.logInfo('Skipping gathering local packages composite deps');

    return {};
  }
}


const getLocalPackagesCompositeDeps = module.exports.getLocalPackagesCompositeDeps = () => {
  tools.logTitle('Parsing composite deps for local packages');

  let deps = {};

  // getting locally mounted packages, don't take into account remotely installed packages (elements remote)
  let packages = configUtils.packages.getPackages().filter((p) => {
    return !p.paths.remoteNodeModules;
  });

  packages = packages.filter(p => !p.skipDependencies);

  packages.forEach(p => {
    tools.logInfo(`Parsing package : ${p.name}`);

    // getting the package composite if any
    const compositeDeps = getLocalPackageCompositeDeps(p);

    deps = { ...deps, ...compositeDeps };

    tools.logInfo('Deps found : ');
    console.log(deps);
  })

  return deps;
}


const getLocalPackageBaseDeps = (pkg) => {
  let pkgJsonFile;

  if (!skipLocalPackagesDeps) {
    if (pkg.standalone) {
      pkgJsonFile = path.join(process.cwd(), 'dependencies-base.json');
    } else {
      if (pkg.child) {
        pkgJsonFile = path.join(process.cwd(), 'packages', pkg.parentPkg, 'packages', pkg.folder || pkg.name, 'dependencies-base.json');
      } else {
        pkgJsonFile = path.join(process.cwd(), 'packages', pkg.name, 'dependencies-base.json');
      }
    }

    if (tools.isFileExists(pkgJsonFile)) {
      tools.logInfo(`found ${pkgJsonFile}, parsing...`);
    }

    return tools.getJsonFileContent(pkgJsonFile) || {};

  } else {
    tools.logInfo('Skipping gathering local packages base deps');

    return {};
  }
}



const getLocalPackagesBaseDeps = module.exports.getLocalPackagesBaseDeps = () => {
  tools.logTitle('Parsing base deps for local packages');

  let deps = {};

  // getting locally mounted packages, don't take into account remotely installed packages (elements remote)
  const packages = configUtils.packages.getPackages().filter((p) => {
    return !p.paths.remoteNodeModules;
  });

  packages.forEach(p => {
    tools.logInfo(`Parsing package : ${p.name}`);

    // getting the package base if any
    const baseDeps = getLocalPackageBaseDeps(p);

    deps = { ...deps, ...baseDeps };

    tools.logInfo('Deps found : ');
    console.log(deps);
  })

  return deps;
}


module.exports.getLocalPackagesCompositeDepsRemapped = () => {
  return Promise.resolve()
    .then(() => {
      const compositeDeps = getLocalPackagesCompositeDeps();

      return innerCommon.getResolvedCarretDeps(compositeDeps, false, true);
    })

    .then((remappedDeps) => {
      tools.logInfo('Remapped deps : ');

      console.log(remappedDeps);

      return remappedDeps;
    })

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

module.exports.getLocalPackageDepsAll = (pkg) => {
  return {
    ...getLocalPackageDeps(pkg),
    ...getLocalPackageBaseDeps(pkg),
    ...getLocalPackageCompositeDeps(pkg)
  };
}

module.exports.installDeps = (prj, pkg, isMaster) => {
  let compositeDeps, localPkgDeps, localPkgCompositeDeps, remappedDeps, localPkgBaseDeps;

  return Promise.resolve()
    .then(() => {
      // when package is built against an app (depends on this app deps defined)
      // the composite deps of that app is returned (default to DEV target)
      if (prj) {
        return innerProjects.getDeps(prj);

      // when package is stand-alone, then we take only the deps from within the package.json
      } else {
        return {};
      }
    })

    .then((deps) => {
      // storing
      compositeDeps = deps;

      tools.logInfo(`Found composite deps : `);
      console.log(JSON.stringify(compositeDeps, null, 2));

      // fetching package own deps
      return getLocalPackagesDeps();
    })


    .then((localPkgDepsIn) => {
      // storing
      localPkgDeps = localPkgDepsIn;

      tools.logInfo(`Found local packages deps : `);
      console.log(JSON.stringify(localPkgDeps, null, 2));

      // fetching local package composite
      return getLocalPackagesCompositeDeps();
    })
    .then((localPkgCompositeDepsIn) => {
      // storing
      localPkgCompositeDeps = localPkgCompositeDepsIn;
    })

    .then(() => {
      return innerCommon.getResolvedCarretDeps(localPkgCompositeDeps, isMaster, !isMaster);
    })

    .then((remappedDepsIn) => {
      // storing
      remappedDeps = remappedDepsIn;

      return getLocalPackagesBaseDeps();
    })

    .then((localPkgBaseDepsIn) => {
      localPkgBaseDeps = localPkgBaseDepsIn;

      // fetching extra dependencies on project if any
      let prjDeps = {};

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

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

      if (pkg.build && pkg.build.ownDepsOnly) {
        return innerCommon.installDeps({ ...localPkgBaseDeps, ...remappedDeps, ...localPkgDeps, ...fixedDeps});

      } else {
        return innerCommon.installDeps({ ...localPkgBaseDeps, ...remappedDeps, ...localPkgDeps, ...prjDeps, ...compositeDeps, ...fixedDeps });
      }
    })

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


module.exports.installDepsStandalone = (pkg, isMaster) => {
  let localPkgDeps, localPkgCompositeDeps, remappedDeps, localPkgBaseDeps;

  if (skipInstall) {
    tools.logInfo('skipInstall active...skipiing');
    return {};
  }

  return Promise.resolve()
    // fetching depedencies composite deps
    .then(() => {
      return getLocalPackageCompositeDeps(pkg);
    })
    // storing
    .then((localPkgCompositeDepsIn) => {
      localPkgCompositeDeps = localPkgCompositeDepsIn;
    })

    // remapping from registry
    .then(() => {
      return innerCommon.getResolvedCarretDepsStandalone(localPkgCompositeDeps, isMaster, !isMaster);
    })
    // storing
    .then((remappedDepsIn) => {
      remappedDeps = remappedDepsIn;
    })

    // fetch dependencies-base deps
    .then(() => {
      return getLocalPackageBaseDeps(pkg);
    })

    .then((localPkgBaseDepsIn) => {
      localPkgBaseDeps = localPkgBaseDepsIn;

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

      return innerCommon.installDepsStandalone(pkg, { ...localPkgBaseDeps, ...remappedDeps, ...localPkgDeps, ...fixedDeps});
    })

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



