'use strict';

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

// local
const tools = require('../../utils/tools');
const templateUtils = require('../templates/template-utils');
const configUtils = require('../config/config-utils');


// constants
const { dryRun, nexusUser, nexusPassword } = tools.getArgs();


const writePackageJsonCore = (newVersion, folder, isSnapshot, isNextBranch, isSupportBranch, isHotfixBranch, envTarget) => {
  return Promise.resolve()
    .then(() => {
      let tag = 'latest';

      if (isSnapshot) {
        tag = `snapshot`;
      } else if (isNextBranch) {
        tag = 'next';
      } else if (isSupportBranch) {
        tag = `v${newVersion.split('.')[0]}-lts`;
      }

      if (dryRun) {
        tools.logInfo(`Updating package.json with : newVersion: ${newVersion} - tag: ${tag}`);

      } else {
        const pkgJsonFile = path.resolve(folder, 'package.json');
        const pkgJson = require(pkgJsonFile);

        pkgJson.version = newVersion;
        pkgJson.tag = tag;

        // This code snippet checks if the package name starts with '@eui' and updates the version of dependencies
        // and peerDependencies accordingly, excluding dependencies that start with '@eui/tools'.
        if(pkgJson.name.startsWith('@eui') && pkgJson.dependencies) {
          Object.keys(pkgJson.dependencies)
            .filter(dep => dep.startsWith('@eui') && !dep.startsWith('@eui/tools'))
            .forEach((dep) => {
              pkgJson.dependencies[dep] = newVersion;
            });
        }
        if(pkgJson.name.startsWith('@eui') && pkgJson.peerDependencies) {
          Object.keys(pkgJson.peerDependencies)
            .filter(dep => dep.startsWith('@eui') && !dep.startsWith('@eui/tools'))
            .forEach((dep) => {
              pkgJson.peerDependencies[dep] = newVersion;
            });
        }

        tools.logInfo(`Updating package version : ${newVersion} / tag: ${tag} for ${pkgJsonFile}`);
        tools.writeJsonFileSync(pkgJsonFile, pkgJson);
      }
    })
    .catch((e) => {
      throw e;
    })
}

const processDependency = (dep) => {
  if(dep.startsWith('@eui')) {
    pkgJson.dependencies[dep] = newVersion;
  }
  return dep;
}

const writePackageJson = (pkg, newVersion, isSnapshot, isNextBranch, isSupportBranch, isHotfixBranch, envTarget) => {
  return Promise.resolve()
    .then(() => {
      tools.logTitle('updating package version');

      if (!pkg.parent) {
        return Promise.resolve()
          .then(() => {
            return writePackageJsonCore(newVersion, pkg.paths.root, isSnapshot, isNextBranch, isSupportBranch, isHotfixBranch, envTarget);
          })
          .then(() => {
            if (!pkg.element && !pkg.config) {
              return writePackageJsonCore(newVersion, pkg.paths.publish, isSnapshot, isNextBranch, isSupportBranch, isHotfixBranch, envTarget);
            }
          })
          .catch((e) => {
            throw e;
          })

      } else {
        return Promise.resolve()
          .then(() => {
            return writePackageJsonCore(newVersion, pkg.paths.root, isSnapshot, isNextBranch, isSupportBranch, isHotfixBranch, envTarget);
          })
          .then(() => {
            let linkedPackages = Object.keys(pkg.packages)
              .map(p => {
                const pkg = configUtils.packages.getPackage(p);
                return pkg;
              })

            return tools.removeArrayDuplicates(linkedPackages, 'name');
          })

          .then((linkedPackages) => Promise.resolve().then(() => {
            return linkedPackages.reduce((promise, pkg) => {
              return promise.then(() => (
                writePackageJsonCore(newVersion, pkg.paths.publish, isSnapshot, isNextBranch, isSupportBranch, isHotfixBranch, envTarget)
              ));
            }, Promise.resolve());
          }))

          .catch((e) => {
            throw e;
          })
      }
    })
    .then(() => {
      tools.logSuccess();
    })
    .catch((e) => {
      throw e;
    })
}



const writePomXml = (pkg, newVersion, isSnapshot, isForceTimestamp = true) => {

  tools.logTitle(`updating project pom.xml version: ${newVersion}`);


  if (dryRun) {
      return;
  }

  return Promise.resolve()
    .then(() => {
      return templateUtils.generateMavenSettings(nexusUser, nexusPassword);
    })

    .then((mavenSettingsFile) => {

      tools.logInfo(`Executing mvn versions on : ${pkg.paths.root}`);

      execa.shellSync('mvn versions:set -T1 -DnewVersion=' + newVersion + ' -s ' + mavenSettingsFile, { cwd: pkg.paths.root });
      execa.shellSync('mvn versions:commit -T1' + ' -s ' + mavenSettingsFile, { cwd: pkg.paths.root });

      if (isForceTimestamp) {
        // timestamp file is forced to have at least one file to commit, as snapshot release
        // for backend can keep the same version until its latest
        const tsversionFile = path.resolve(pkg.paths.root, '.tsversion');
        tools.writeFileContent(tsversionFile, Date.now().toString());

        const versionFile = path.resolve(pkg.paths.root, '.version.properties');
        tools.writeFileContent(versionFile, newVersion);
      }
    })
    .then(() => {
      tools.logSuccess();
    })
    .catch((e) => {
      throw e;
    })
}



module.exports.updateVersion = (pkg, newVersion, isSnapshot, isNextBranch, isSupportBranch, isHotfixBranch, envTarget) => {
  try {
    if (pkg.backend) {
      return writePomXml(pkg, newVersion, isSnapshot);
    }
    else {
      return writePackageJson(pkg, newVersion, isSnapshot, isNextBranch, isSupportBranch, isHotfixBranch, envTarget);
    }
  } catch(e) {
    throw e;
  }
}


module.exports.getCurrentVersion = (pkg) => {
  return Promise.resolve()
    .then(() => {
      let currentVersion;

      tools.logTitle('Extracting current version');

      if (pkg.backend) {
        // if nodejs backend, explicitely declared
        if (pkg.build && pkg.build.nodejs) {
          tools.logInfo('UI package => extracting from package.json');

          const pathPkgJson = path.resolve(pkg.paths.root, 'package.json');
          const pkgJson = require(pathPkgJson);
          currentVersion = pkgJson.version;

          // by default maven java backend is taken into account
        } else {
          tools.logInfo('Backend => extracting pom.xml');
          const xmlContent = tools.getXMLJsContent(path.join(pkg.paths.root, 'pom.xml'));

          tools.logInfo('Content found:');
          console.log(xmlContent);

          currentVersion = xmlContent.project.version.toString();
        }

      } else {
        tools.logInfo('UI package => extracting from package.json');

        const pathPkgJson = path.resolve(pkg.paths.root, 'package.json');
        const pkgJson = require(pathPkgJson);
        currentVersion = pkgJson.version;
      }

      tools.logSuccess('Current version found : ' + currentVersion);
      return currentVersion;
    })
    .catch((e) => {
      throw e;
    })
}

