'use strict';

// externals
const semver = require('semver');

// local
const tools = require('../../utils/tools');


const getNewVersionForDev = (versionsMetadata, envsMetadata, rootEnv, currentVersion) => {
  let version;
  const lastIntMetadata = envsMetadata[rootEnv];

  if (lastIntMetadata) {
    tools.logInfo(`Last ${rootEnv} metadata found`);
    const rootVersion = semver.coerce(envsMetadata[rootEnv].version).raw;
    version = semver.inc(rootVersion, 'major') + '-SNAPSHOT';
    tools.logInfo(`base version : ${version}`);

  } else {
    tools.logInfo(`No ${rootEnv} metadata found : initializing version`);
    if (currentVersion) {
      version = semver.coerce(currentVersion).raw + '-SNAPSHOT';
    } else {
      version = '1.0.0-SNAPSHOT';
    }
    tools.logInfo(`version intialized : ${version}`);
  }

  // if no versions history is found for the current project, initial version is set
  if (!versionsMetadata.versions) {
    tools.logSuccess(`No historical version found : version = ${version}`);
    version += '.0';

  } else {
    // check if the root version already exsists
    const prevVersions = versionsMetadata.versions.filter((v) => {
      return v.version.indexOf(version) > -1;
    });

    // do the increment over the last version found having the same root version
    if (prevVersions.length) {
      const lastVersion = prevVersions[prevVersions.length - 1];

      if (lastVersion) {
        tools.logInfo(`Version already found [${lastVersion.version}]`);
        version = semver.inc(lastVersion.version, 'prerelease');
        tools.logSuccess(`Final version : ${version}`);
      }

      // if it's a branch new DEV stream release, the snapshot is itialized
    } else {
      tools.logInfo(`prevVersions matching: ${version} not found initializing first release of raw version`);
      version += '.0';
    }
  }

  return version;
}

const getNewVersionForProd = (versionsMetadata, envsMetadata) => {
  let version;

  // get the last DEV version from env metadata
  const lastAccVersion = envsMetadata['ACC'].version;

  tools.logInfo(`Fetched last version from ACC : ${lastAccVersion}`);

  // coerce the version (X.Y.Z-INT.n will generate : X.Y.Z)
  const rootVersion = semver.coerce(lastAccVersion).raw;
  const tempVersion = rootVersion.split('.');
  const rootVersionMinor = `${tempVersion[0]}.${tempVersion[1]}`;

  // check if the root version already exists
  const prevVersions = versionsMetadata.versions.filter((v) => {
    return v.version.indexOf(rootVersionMinor) > -1 && v.envTarget === 'PROD';
  });

  if (prevVersions.length) {
    const lastVersion = prevVersions[prevVersions.length - 1];

    tools.logInfo(`Version already found [${lastVersion.version}]`);
    version = semver.inc(lastVersion.version, 'patch');
    tools.logInfo(`Incremented version : ${version}`);

  } else {
    version = rootVersion;
  }

  tools.logSuccess(`Final version : ${version}`);

  return version;
}


const getNewVersionForEnv = (versionsMetadata, envsMetadata, rootEnv, envTarget) => {
  let version;

  tools.logInfo(`Fetching version from rootEnv: ${rootEnv} for target: ${envTarget}`);

  // check if envMetadata contains data for the rootEnv
  if (!envsMetadata[rootEnv]) {
    throw new Error(`No metadata found for rootEnv: ${rootEnv} for envTarget build: ${envTarget}`);
  }

  // get the last DEV version from env metadata
  const lastRootEnvVersion = envsMetadata[rootEnv].version;

  tools.logInfo(`Fetched last version from ${rootEnv} : ${lastRootEnvVersion}`);

  // coerce the version (X.Y.Z-SNAPSHOT will generate : X.Y.Z)
  const rootVersion = semver.coerce(lastRootEnvVersion).raw;

  // check if the root version already exists
  const prevVersions = versionsMetadata.versions.filter((v) => {
    return v.version.indexOf(rootVersion) > -1 && v.envTarget === envTarget;
  });

  if (prevVersions.length) {
    const lastVersion = prevVersions[prevVersions.length - 1];

    tools.logInfo(`Version already found [${lastVersion.version}]`);
    version = semver.inc(lastVersion.version, 'prerelease');
    tools.logInfo(`Incremented version : ${version}`);

  } else {
    version = rootVersion + '-' + envTarget + '.0';
  }

  tools.logSuccess(`Final version : ${version}`);

  return version;
}




module.exports.getNewVersionDefault = (envTarget, versionsMetadata, envsMetadata, currentVersion) => {
  tools.logInfo(`Retrieve version for ${envTarget}`);

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

      // =====================================================================
      // DEV target : format : X.Y.Z-SNAPSHOT.n
      //  - where X.Y.Z is last INT release next MAJOR version
      // =====================================================================

      if (envTarget === 'DEV') {
        version = getNewVersionForDev(versionsMetadata, envsMetadata, 'INT', currentVersion);
      }


      // =====================================================================
      // TST target : format : X.Y.Z-TST.n
      //   - where X.Y.Z is the last root version of DEV env target
      // =====================================================================

      if (envTarget === 'TST') {
        version = getNewVersionForEnv(versionsMetadata, envsMetadata, 'DEV', 'TST');
      }


      // =====================================================================
      // INT target : format : X.Y.Z-INT.n
      //   - where X.Y.Z is the last root version of TST env target
      // =====================================================================

      if (envTarget === 'INT') {
        version = getNewVersionForEnv(versionsMetadata, envsMetadata, 'TST', 'INT');
      }


      // =====================================================================
      // ACC target : format : X.Y.Z-envTarget.n
      //   - where X.Y.Z is the last root version of INT env target
      // =====================================================================

      if (envTarget === 'ACC') {
        version = getNewVersionForEnv(versionsMetadata, envsMetadata, 'INT', 'ACC');
      }

      // =====================================================================
      // DLT targets : format : X.Y.Z-envTarget.n
      //   - where X.Y.Z is the last root version of ACC env target
      // =====================================================================

      if (envTarget === 'DLT') {
        version = getNewVersionForEnv(versionsMetadata, envsMetadata, 'ACC', 'DLT');
      }

      // =====================================================================
      // TRN targets : format : X.Y.Z-envTarget.n
      //   - where X.Y.Z is the last root version of ACC env target
      // =====================================================================

      if (envTarget === 'TRN') {
        version = getNewVersionForEnv(versionsMetadata, envsMetadata, 'ACC', 'TRN');
      }

      // =====================================================================
      // PPD targets : format : X.Y.Z-envTarget.n
      //   - where X.Y.Z is the last root version of ACC env target
      // =====================================================================

      if (envTarget === 'PPD') {
        version = getNewVersionForEnv(versionsMetadata, envsMetadata, 'ACC', 'PPD');
      }

      // =====================================================================
      // FOR PROD : format X.Y.Z(+1)
      //   - where X.Y.Z is the last version of PROD with the same INT root
      // =====================================================================

      if (envTarget === 'PROD') {
        version = getNewVersionForProd(versionsMetadata, envsMetadata);
      }

      // Check if version has been found, it can never be empty
      if (!version) {
        throw new Error(`Unable to generate version for ${envTarget}`);
      }

      return version;
    })

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



module.exports.getNewVersionDTAP = (envTarget, versionsMetadata, envsMetadata) => {
  tools.logInfo(`Retrieve version for ${envTarget}`);

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

      // =====================================================================
      // DEV target : format : X.Y.Z-SNAPSHOT.n
      //  - where X.Y.Z is last INT release next MAJOR version
      // =====================================================================

      if (envTarget === 'DEV') {
        version = getNewVersionForDev(versionsMetadata, envsMetadata, 'TST');
      }


      // =====================================================================
      // TST target : format : X.Y.Z-TST.n
      //   - where X.Y.Z is the last root version of DEV env target
      // =====================================================================

      if (envTarget === 'TST') {
        version = getNewVersionForEnv(versionsMetadata, envsMetadata, 'DEV', 'TST');
      }


      // =====================================================================
      // ACC target : format : X.Y.Z-envTarget.n
      //   - where X.Y.Z is the last root version of INT env target
      // =====================================================================

      if (envTarget === 'ACC') {
        version = getNewVersionForEnv(versionsMetadata, envsMetadata, 'TST', 'ACC');
      }


      // =====================================================================
      // FOR PROD : format X.Y.Z(+1)
      //   - where X.Y.Z is the last version of PROD with the same INT root
      // =====================================================================

      if (envTarget === 'PROD') {
        version = getNewVersionForProd(versionsMetadata, envsMetadata);
      }

      // Check if version has been found, it can never be empty
      if (!version) {
        throw new Error(`Unable to generate version for ${envTarget}`);
      }

      return version;
    })

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


