'use strict';

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

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

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

const getInstallRegistry = () => {
  const NPM_REGISTRY_INSTALL = configUtils.global.getConfigOptions().NPM_REGISTRY_INSTALL;

  // check if registry has been passed as argument
  let installRegistry;
  if (registry) {
    installRegistry = registry;
  // } else {
  //   installRegistry = NPM_REGISTRY_INSTALL;
  }

  return installRegistry;
};

module.exports.installDeps = (deps) => {
  return (
    Promise.resolve()

      // parse eUI deps and explode the sub-packages (v17 issues)
      .then(() => {
        const euiVersion = configUtils.global.getLocalEuiVersion();
        const euiVersionNumber = parseInt(euiVersion);

        if (euiVersionNumber >= 17) {
          Object.keys(deps).forEach((dep) => {
            if (dep === '@eui/deps-base') {
              deps['@eui/components'] = deps[dep];
              deps['@eui/showcase'] = deps[dep];
              deps['@eui/styles'] = deps[dep];
            }
          });
        }

        // special injection for eslint builder missing / clash with eslint version from eUI / others sub-libs
        if (euiVersionNumber === 18) {
          deps["@angular-eslint/builder"] = "18.3.0";
          deps["@angular-eslint/eslint-plugin"] = "18.3.0";
          deps["@angular-eslint/eslint-plugin-template"] = "18.3.0";
          deps["@angular-eslint/schematics"] = "18.3.0";
          deps["@angular-eslint/template-parser"] = "18.3.0";
          deps["eslint-plugin-prefer-arrow"] = "1.2.3";
          deps["eslint-plugin-jsdoc"] = "48.7.0";
          deps["@typescript-eslint/parser"] = "7.16.1";
          deps["@typescript-eslint/eslint-plugin"] = "7.16.1";
        }
      })

      // Install dependencies
      .then(() => {
        tools.logTitle('Package dependencies to install : ');

        const rootFolder = process.cwd();
        const pkgJsonFile = path.resolve(rootFolder, 'package.json');
        const pkgJson = require(pkgJsonFile);

        pkgJson.dependencies = deps;

        // Updating file and installing
        if (Object.keys(pkgJson.dependencies).length !== 0) {
          tools.writeJsonFileSync(pkgJsonFile, pkgJson);
          tools.logInfo('installing dependencies');
          console.log(pkgJson.dependencies);

          return executeInstall(rootFolder);
        }
      })

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


module.exports.installDepsStandalone = (pkg, deps) => {
  const rootFolder = process.cwd();
  const pkgJsonFile = path.resolve(rootFolder, 'package.json');
  const pkgJson = require(pkgJsonFile);

  return (
    Promise.resolve()
      // parse eUI deps and explode the sub-packages (v17 issues)
      .then(() => {
        const euiVersion = configUtils.packages.getPackageEuiVersion(pkg);
        const euiVersionNumber = parseInt(euiVersion);

        if (euiVersionNumber >= 17) {
          Object.keys(deps).forEach((dep) => {
            if (dep === '@eui/deps-base') {
              deps['@eui/components'] = deps[dep];
              deps['@eui/showcase'] = deps[dep];
              deps['@eui/styles'] = deps[dep];
            }
          });
        }
      })

      // Install dependencies
      .then(() => {
        tools.logTitle('Package dependencies to install : ');
        pkgJson.dependencies = deps;

        // Updating file and installing
        if (Object.keys(pkgJson.dependencies).length !== 0) {
          tools.writeJsonFileSync(pkgJsonFile, pkgJson);
          tools.logInfo('installing dependencies');
          console.log(pkgJson.dependencies);

          return executeInstall(rootFolder, configUtils.global.getConfigOptionsStandalone().NPM_REGISTRY_INSTALL);
        }
      })

      .then(() => {
        pkgJson.dependencies = {}
        pkgJson.resolutions = {}
        tools.writeJsonFileSync(pkgJsonFile, pkgJson);
      })

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



const executeInstall = (module.exports.executeInstall = (cwdPath, npmRegistry) => {
  return Promise.resolve()
    .then(() => {
      let installRegistry;

      if (npmRegistry) {
        installRegistry = npmRegistry;
      } else {
        installRegistry = getInstallRegistry();
      }

      tools.logInfo(`Install from : ${installRegistry}`);
      if (!dryRun && !skipInstall) {
        if (installRegistry) {
          return execa.shellSync(`yarn --registry ${installRegistry}`, { cwd: cwdPath, stdio: 'inherit' });
        } else {
          return execa.shellSync(`yarn`, { cwd: cwdPath, stdio: 'inherit' });
        }
      } else {
        tools.logInfo(`Skipping install - Executing command : yarn --registry ${installRegistry}`);
      }
    })

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

module.exports.executeInstallPackage = (cwdPath, npmPkg) => {
  return Promise.resolve()
    .then(() => {
      const installRegistry = getInstallRegistry();

      tools.logInfo(`Install ${npmPkg} from : ${installRegistry}`);
      if (!dryRun && !skipInstall) {
        return execa.shellSync(`yarn add ${npmPkg} --no-lockfile --registry ${installRegistry}`, { cwd: cwdPath, stdio: 'inherit' });
      }
    })

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

module.exports.getResolvedCarretDeps = (deps, isMaster, isDevEnvTarget) => {
  tools.logTitle('Resolving carret versions of detected packages');

  tools.logInfo('processing dependencies : ');
  console.log(deps);

  return (
    Promise.resolve()
      .then(() => {
        const dependencies = Object.keys(deps).reduce((acc, k) => {
          if (deps[k] && deps[k].substr(0, 1) === '^') {
            const npmPkg = k;
            const version = deps[k];

            tools.logInfo(`\nProcessing ${npmPkg}:${version}`);

            // getting package from npmPkg
            const pkg = configUtils.packages.getPackageByNpmPkg(npmPkg, true);

            if (!pkg) {
              tools.logWarning(`npmPkg: ${npmPkg} is not a CSDR package`);

            } else {
              // getting last major version from metadata history for pkg found
              const lastMajorVersion = metadataUtils.packageUtils.getLastMajorVersion(
                pkg,
                version.substr(1).split('.')[0],
                isMaster,
                isDevEnvTarget
              );

              if (lastMajorVersion) {
                tools.logInfo(`--version found : ${lastMajorVersion}`);
                acc[k] = lastMajorVersion;
              } else {
                tools.logWarning(`WARNING : Can't resolve carret version from history for pkg: ${npmPkg} for version ${version}`);
              }
            }
          }
          return acc;
        }, {});

        return { ...deps, ...dependencies };
      })

      // don't rethrow in case of error, just log the exception
      .catch((e) => {
        tools.logError('Unable to resolve deps');
        console.log(e);
        return deps;
      })
  );
};


module.exports.getResolvedCarretDepsStandalone = (deps, isMaster, isDevEnvTarget) => {
  tools.logTitle('Resolving carret versions of detected packages');

  tools.logInfo('processing dependencies : ');
  console.log(deps);

  return (
    Promise.resolve()
      .then(() => {
        const dependencies = Object.keys(deps).reduce((acc, k) => {
          if (deps[k] && deps[k].substr(0, 1) === '^') {
            const npmPkg = k;
            const version = deps[k];

            tools.logInfo(`\nProcessing ${npmPkg}:${version}`);

            // getting last major version from metadata history for pkg found
            const lastMajorVersion = metadataUtils.packageUtils.getLastMajorVersionByNpmPkg(
              npmPkg,
              version.substr(1).split('.')[0],
              isMaster,
              isDevEnvTarget
            );

            if (lastMajorVersion) {
              tools.logInfo(`--version found : ${lastMajorVersion}`);
              acc[k] = lastMajorVersion;
            } else {
              tools.logWarning(`WARNING : Can't resolve carret version from history for pkg: ${npmPkg} for version ${version}`);
            }
          }
          return acc;
        }, {});

        return { ...deps, ...dependencies };
      })

      // don't rethrow in case of error, just log the exception
      .catch((e) => {
        tools.logError('Unable to resolve deps');
        console.log(e);
        return deps;
      })
  );
};
