'use strict';

const path = require('path');

const tools = require('../../tools');
const gitUtils = require('../../git-utils');
const configUtils = require('../../../csdr/config/config-utils');

const { skipPull } = tools.getArgs();

const injectExternalAppSourcesCore = (project, build = false, injectedNpmPkg, injectedFolder, euiVersion) => {

  tools.logInfo(`Injecting app sources : ${injectedNpmPkg} / ${injectedFolder} for eUI verison : ${euiVersion}`);

  return Promise.resolve()
  .then(() => {
    // check if package is locally cloned
    const localPackage = configUtils.packages.getPackages().filter((p) => {
      return p.npmPkg === injectedNpmPkg
    })[0];

    let appSourcesSrcPath;
    const projectRootPath = path.join(process.cwd(), project.folder);
    const projectSrcPath = path.join(projectRootPath, 'src');

    // if local package is found
    if (localPackage) {
      tools.logInfo('local project found, copying from local');

      if (euiVersion) {
        appSourcesSrcPath = path.join(process.cwd(), 'packages', localPackage.name, 'assets', euiVersion, injectedFolder);
      } else {
        // maintain old compat for transition
        if (injectedFolder.indexOf('assets') > -1) {
          appSourcesSrcPath = path.join(process.cwd(), 'packages', localPackage.name, injectedFolder);
        } else {
          appSourcesSrcPath = path.join(process.cwd(), 'packages', localPackage.name, 'assets', injectedFolder);
        }
      }

    // if not sources are taken from the npm package def in node_modules
    } else {
      tools.logInfo('remote project found, copying from remote');

      const npmPkgScope = injectedNpmPkg.substr(0, injectedNpmPkg.indexOf('/'));
      const npmPkgName = injectedNpmPkg.substr(injectedNpmPkg.indexOf('/') + 1);

      if (euiVersion) {
        appSourcesSrcPath = path.join(process.cwd(), 'node_modules', npmPkgScope, npmPkgName, 'assets', euiVersion, injectedFolder);
      } else {
        // maintain old compat for transition
        if (injectedFolder.indexOf('assets') > -1) {
          appSourcesSrcPath = path.join(process.cwd(), 'node_modules', npmPkgScope, npmPkgName, injectedFolder);
        } else {
          appSourcesSrcPath = path.join(process.cwd(), 'node_modules', npmPkgScope, npmPkgName, 'assets', injectedFolder);
        }
      }
    }

    if (!tools.isDirExists(appSourcesSrcPath)) {
      tools.logWarning(`External sources location : ${appSourcesSrcPath} cannot be found in node_modules`);
      throw new Error('External sources not found');

    } else {

      return Promise.resolve()
        // inject sources from sources to target location in app
        .then(() => {
          tools.logInfo(`${appSourcesSrcPath} injecting in ${projectSrcPath}`);
          return tools.copydir(appSourcesSrcPath, projectSrcPath, true);
        })

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

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


const injectExternalAppRootCore = (project, build = false, injectedNpmPkg, injectedFolder, euiVersion) => {

  tools.logInfo(`Injecting app root files : ${injectedNpmPkg} / ${injectedFolder} - eUI version : ${euiVersion}`);

  return Promise.resolve()
  .then(() => {
    // check if package is locally cloned
    const localPackage = configUtils.packages.getPackages().filter((p) => {
      return p.npmPkg === injectedNpmPkg
    })[0];

    let appRootSrcPath;
    const projectRootPath = path.join(process.cwd(), project.folder);

    // if local package is found
    if (localPackage) {
      tools.logInfo('local project found, copying from local');

      if (euiVersion) {
        appRootSrcPath = path.join(process.cwd(), 'packages', localPackage.name, 'assets', euiVersion, injectedFolder);
      } else {
        appRootSrcPath = path.join(process.cwd(), 'packages', localPackage.name, 'assets', injectedFolder);
      }

    // if not sources are taken from the npm package def in node_modules
    } else {
      tools.logInfo('remote project found, copying from remote');

      const npmPkgScope = injectedNpmPkg.substr(0, injectedNpmPkg.indexOf('/'));
      const npmPkgName = injectedNpmPkg.substr(injectedNpmPkg.indexOf('/') + 1);

      if (euiVersion) {
        appRootSrcPath = path.join(process.cwd(), 'node_modules', npmPkgScope, npmPkgName, 'assets', euiVersion, injectedFolder);
      } else {
        appRootSrcPath = path.join(process.cwd(), 'node_modules', npmPkgScope, npmPkgName, 'assets', injectedFolder);
      }
    }

    if (!tools.isDirExists(appRootSrcPath)) {
      tools.logWarning(`External sources location : ${appRootSrcPath} cannot be found in node_modules`);
      throw new Error('External sources not found');

    } else {

      return Promise.resolve()
        .then(() => {
          tools.logInfo('Injecting app root files...');

          return tools.copydirFiles(appRootSrcPath, projectRootPath, true);
        })

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

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





module.exports.injectExternalAppSources = (project, build = false, init = false, euiVersion) => {

  if (!project.externalSources) {
    tools.logInfo('No external app sources setup...skipping');
    return;
  }

  if (project.externalSourcesOnInit === false && init) {
    tools.logInfo('Project as not external sources pulling on init phase...skipping');
    return;
  }

  if (!euiVersion) {
    const { euiVersionArg } = tools.getArgs();
    if (!euiVersionArg && project.virtual) {
      euiVersion = configUtils.projects.getProjectEuiVersion(project);

      if (!euiVersion) {
        throw new Error(`
          eUI version of ${project.name} cannot be found...
          if you're initializing the project, pass the "euiVersion" as parameter :
          f.e. : npm run init -- --project ${project.name} .... --euiVersion 10.x
        `);
      }
    }
  }

  tools.logTitle(`Injecting project external application sources for : ${project.name} for eUI version : ${euiVersion}`);

  return Promise.resolve()
    .then(() => {
      if (!build) {
        // removing previously injected content, except assets
        const projectSrcPath = path.join(process.cwd(), project.folder, 'src');
        const projectSrcAppPath = path.join(projectSrcPath, 'app');
        const projectSrcConfigPath = path.join(projectSrcPath, 'config');
        const projectSrcEnvironmentsPath = path.join(projectSrcPath, 'environments');

        return Promise.resolve()
          .then(() => {
            tools.logInfo(`Removing ${projectSrcAppPath} content`);
            return tools.rimraf(projectSrcAppPath);
          })
          .then(() => {
            tools.logInfo(`Removing ${projectSrcConfigPath} content`);
            return tools.rimraf(projectSrcConfigPath);
          })
          .then(() => {
            tools.logInfo(`Removing ${projectSrcEnvironmentsPath} content`);
            return tools.rimraf(projectSrcEnvironmentsPath);
          })
          .catch((e) => {
            throw e;
          })
      }
    })

    .then(() => {
      if (!Array.isArray(project.externalSources)) {
        throw new Error('externalSources present but not an array...stopping');

      } else {
        return Promise.resolve().then(() => {
          return project.externalSources.reduce((promise, appSource) => {
            return promise.then(() => (
              injectExternalAppSourcesCore(project, build, appSource.npmPkg, appSource.folder, euiVersion)
            ));
          }, Promise.resolve());
        })
      }
    })

    // inject external root files (optional)
    .then(() => {
      if (!project.externalRootFiles) {
        tools.logInfo('No external app root files setup...skipping');
        return;
      }

      // in case of multiple injection are defined, we promise loop on each injection
      if (!Array.isArray(project.externalRootFiles)) {
        throw new Error('externalSources present but not an array...stopping');

      } else {
        return Promise.resolve().then(() => {
          return project.externalRootFiles.reduce((promise, appRootFiles) => {
            return promise.then(() => (
              injectExternalAppRootCore(project, build, appRootFiles.npmPkg, appRootFiles.folder, euiVersion)
            ));
          }, Promise.resolve());
        })
      }
    })

    .then(() => {
      tools.logInfo('Check angular-config.json replacement of project');

      const angularConfigFile = path.join(process.cwd(), project.folder, 'angular-config.json');
      delete require.cache[angularConfigFile];
      let angularConfigJson = tools.getJsonFileContent(angularConfigFile);
      angularConfigJson = JSON.stringify(angularConfigJson, null, 2);
      angularConfigJson = tools.replaceAll(angularConfigJson, '@project.name@', project.name);

      return tools.writeFileContent(angularConfigFile, angularConfigJson);
    })

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


module.exports.injectElementExternalSources = (pkg) => {

  tools.logTitle(`Injecting package external sources for : ${pkg.name}`);

  return Promise.resolve()
    .then(() => {
      if (!pkg.externalSources) {
        tools.logInfo('No external sources setup...skipping');
        return;
      }

      if (!pkg.externalSources.npmPkg || !pkg.externalSources.folder) {
        return tools.logWarning('External sources use requires a source [npmPkg] and a [folder] declared');

      } else {
        // check if package is locally cloned
        const localPackage = configUtils.packages.getPackages().filter((p) => {
          return p.npmPkg === pkg.externalSources.npmPkg
        })[0];

        let externalSourcesSrcPath;
        const pkgSrcPath = path.join(pkg.paths.root, 'src');

        // if local package is found
        if (localPackage) {
          tools.logInfo('local pkg found, copying from local');
          externalSourcesSrcPath = path.join(process.cwd(), 'packages', localPackage.name, pkg.externalSources.folder);

        // if not sources are taken from the npm package def in node_modules
        } else {
          tools.logInfo('remote pkg found, copying from remote');
          const npmPkgScope = pkg.externalSources.npmPkg.substr(0, pkg.externalSources.npmPkg.indexOf('/'));
          const npmPkgName = pkg.externalSources.npmPkg.substr(pkg.externalSources.npmPkg.indexOf('/') + 1);

          externalSourcesSrcPath = path.join(pkg.paths.root, 'node_modules', npmPkgScope, npmPkgName, pkg.externalSources.folder);
        }

        if (!tools.isDirExists(externalSourcesSrcPath)) {
          tools.logWarning(`External sources location : ${externalSourcesSrcPath} cannot be found in node_modules`);
          throw new Error('External sources not found');

        } else {
          if (!pkg.fullSkeletonSources) {
            if (tools.isDirExists(pkgSrcPath)) {
              tools.logInfo(`Removing ${pkgSrcPath} content`);
              tools.rmdirFull(pkgSrcPath, false);
            }
          }

          tools.logInfo(`${externalSourcesSrcPath} injecting in ${pkgSrcPath}`);
          return tools.copydir(externalSourcesSrcPath, pkgSrcPath, true);
        }
      }
    })

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


module.exports.injectExternalFeatures = (project) => {

  tools.logTitle(`Injecting project external features for : ${project.name}`);

  return Promise.resolve()
    .then(() => {
      if (!project.features) {
        tools.logInfo('No external features setup...skipping');
        return;
      }

      if (!project.features.npmPkg || !project.features.folder) {
        return tools.logWarning('External features use requires a source [npmPkg] and a [folder] declared');

      } else {
        // check if package is locally cloned
        const localPackage = configUtils.packages.getPackages().filter((p) => {
          return p.npmPkg === project.features.npmPkg
        })[0];

        var featuresSrcPath;
        const projectSrcPath = path.join(process.cwd(), project.folder, 'src', 'app', 'features');

        // if local package is found
        if (localPackage) {
          tools.logInfo('local project found, copying from local');
          featuresSrcPath = path.join(process.cwd(), 'packages', localPackage.name, project.features.folder);

        // if not sources are taken from the npm package def in node_modules
        } else {
          tools.logInfo('remote project found, copying from remote');
          const npmPkgScope = project.features.npmPkg.substr(0, project.features.npmPkg.indexOf('/'));
          const npmPkgName = project.features.npmPkg.substr(project.features.npmPkg.indexOf('/') + 1);

          featuresSrcPath = path.join(process.cwd(), 'node_modules', npmPkgScope, npmPkgName, project.features.folder);
        }

        if (!tools.isDirExists(featuresSrcPath)) {
          tools.logWarning(`External features location : ${featuresSrcPath} cannot be found in node_modules`);
          throw new Error('External features not found');

        } else {
          tools.logInfo(`Removing ${projectSrcPath} content`);
          tools.rmdirFull(projectSrcPath, false);

          tools.logInfo(`${featuresSrcPath} injecting in ${projectSrcPath}`);
          return tools.copydir(featuresSrcPath, projectSrcPath, true);
        }
      }
    })
    .catch((e) => {
      throw e;
    })
}



module.exports.injectExternalMock = (project) => {
  if (skipPull) {
    return;
  }

  tools.logTitle(`Injecting project external mock for : ${project.name}`);

  return Promise.resolve()
    .then(() => {
      if (!project.mock) {
        tools.logInfo('No external mock setup...skipping')

      } else {
        if (project.mock.npmPkg && project.mock.folder) {
          const localPackage = configUtils.packages.getPackages().filter((p) => {
            return p.npmPkg === project.mock.npmPkg
          })[0];

          tools.copydir(
            path.join(process.cwd(), 'packages', localPackage.name, project.mock.folder),
            path.join(process.cwd(), project.folder, 'mock')
          );

        } else {
          return gitUtils.cloneRepo(project.mock.repository, project.mock.folder, false, true);
        }
      }
    })

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