'use strict';

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

// LOCAL
const tools = require('../../tools');
const notificationUtils = require('../../notification/notification-utils');
const cleanUtils = require('../../clean/clean-utils');
const auditUtils = require('../../../csdr/audit/audit-utils');

module.exports.build = (pkg, isMaster) => {

  tools.logInfo('Building UI Angular package...');

  const ng = path.resolve(process.cwd(), 'node_modules', '@angular', 'cli', 'bin', 'ng');

  // FETCH ARGS
  let { deps, skipClean, skipLint, skipTest, skipCompile, skipDoc, build, skipAudit } = pkg.build? {...pkg.build, ...tools.getArgs()} : tools.getArgs();

  let auditStylesReport;

  // standalone switch of eslint / temp solution, as angular.json eslintconfig file is not taken into account
  const swapEslintStandalone = (reset = false) => {
    const eslintStandalone = path.join(pkg.paths.root, '.eslintrc.standalone.json');
    const eslint = path.join(pkg.paths.root, '.eslintrc.json');
    const eslinttemp = path.join(pkg.paths.root, '.eslintrc.temp.json');

    tools.logInfo('Swap eslint config for standalone release of pkg');

    if (reset) {
      tools.logInfo(`copy : ${eslinttemp} tp ${eslint}`);
      tools.copy(eslinttemp, eslint);
      tools.logInfo(`delete : ${eslinttemp}`);
      tools.remove(eslinttemp);
    } else {
      tools.logInfo(`copy : ${eslint} tp ${eslinttemp}`);
      tools.copy(eslint, eslinttemp);
      tools.logInfo(`move : ${eslintStandalone} tp ${eslint}`);
      tools.copy(eslintStandalone, eslint);
    }
  }

  return Promise.resolve()
    .then(() => {
      if (deps === true) {
        tools.logInfo('Building dependencies...');
        return tools.runScript(`eui-scripts build-deps ${pkg.name}`);
      }
    })
    .then(() => {
      if (!skipClean && !skipCompile) {
        tools.logInfo('Cleaning...');
        return cleanUtils.cleanPackage(pkg);
      }
    })
    .then(() => {
      if (!skipLint) {
        tools.logInfo('Linting...');

        const tsLintPath = path.join(pkg.paths.root, 'tslint.json');
        const esLintPath = path.join(pkg.paths.root, '.eslintrc.json');
        const esLintPathMjs = path.join(pkg.paths.root, 'eslint.config.mjs');

        if (tools.isFileExists(tsLintPath)) {
          // TODO: remove TSLint since it's deprecated and should not be used by projects in the future
          tools.logWarning('TSLint is deprecated and will be removed in the future. Consider migrating to ESLint')
          const script = `tslint -c ${tsLintPath} -p ${pkg.paths.tsConfig} -t verbose`
          tools.logInfo(`running ${script}`);
          return tools.runScript(script);

        } else if(tools.isFileExists(esLintPath) || tools.isFileExists(esLintPathMjs)) {
          // the project path information are located inside the .eslintrc.json
          tools.logInfo(`running ng lint ${pkg.name}`);

          return Promise.resolve()
            .then(() => {
              if (pkg.standalone) {
                swapEslintStandalone();
              }
            })
            .then(() => {
              if (build && pkg.msteamsActive) {
                let args = ['--max_old_space_size=8096', ng, 'lint', pkg.name];
                return tools.runNodeScriptProcessOutput(args, pkg.paths.root);

              } else {
                return tools.runScript(`ng lint ${pkg.name}`);
              }
            })

            .then(() => {
              if (!skipLint) {
                tools.logSuccess();
                if (pkg.standalone) {
                  swapEslintStandalone(true);
                }
              }
            })

            .catch((e) => {
              if (pkg.standalone) {
                swapEslintStandalone(true);
              }
              throw e;
            })

        } else {
          tools.logError(`No ESLint or TSLint configuration found for the project`);
        }
      }
    })
    .then(() => {
      if (!skipAudit) {
        return auditUtils.styles.audit(pkg);
      }
    })
    .then((report) => {
      if (report) {
        auditStylesReport = report;
      }

      if (!skipTest) {
        tools.logInfo('Testing...');

        let args = ['--max_old_space_size=8096', ng, 'test', pkg.name];
        args.push('--code-coverage');
        tools.logInfo(`running ng test : with args: ${args} on folder : ${pkg.paths.root}`);

        if (build && pkg.msteamsActive) {
          return tools.runNodeScriptProcessOutput(args, pkg.paths.root);

        } else {
          return execa('node', args, { cwd: pkg.paths.root, stdio: 'inherit' });
        }
      }
    })
    .then(() => {
      if (!skipTest) {
        tools.logSuccess();
      }

      if (!skipCompile) {
        tools.logInfo('Bundling package...');
        let args = ['--max_old_space_size=8096', ng, 'build', pkg.name];

        tools.logInfo(`running ng build : with args: ${args} on folder : ${pkg.paths.root}`);

        if (build && pkg.msteamsActive) {
          return tools.runNodeScriptProcessOutput(args, pkg.paths.root);

        } else {
          return execa('node', args, { cwd: pkg.paths.root, stdio: 'inherit' });
        }
      }
    })
    .then(() => {
      if (!skipCompile) {
        tools.logSuccess();
      }
      if (!skipDoc && (pkg.build && pkg.build.generateDoc)) {
        tools.logInfo('Generating Compodoc documentation for package...');

        const docDistPath = path.join(pkg.paths.root, 'dist', 'docs');

        return Promise.resolve()
          .then(() => {
            return tools.rimraf(docDistPath);
          })
          .then(() => {
            return tools.runScript(`compodoc -p ${pkg.paths.root}/${pkg.tsConfigFileName} -d ${docDistPath} --theme material --disableGraph --disableCoverage --disableSourceCode --disableDomTree --disableProtected --disablePrivate --disableLifeCycleHooks --disableTemplateTab --disableStyleTab --hideGenerator --toggleMenuItems all`);
          })
          .then(() => {
            tools.logSuccess();
          })
          .catch((e) => {
            throw e;
          })
      }
    })
    .then(() => {
      if (!skipCompile) {
        tools.logInfo('Copying assets...');
        tools.copydir(path.join(pkg.paths.root, 'assets'), path.join(pkg.paths.root, 'dist', 'assets'));

        tools.logInfo('Copying config...');
        tools.copydir(path.join(pkg.paths.root, 'config'), path.join(pkg.paths.root, 'dist', 'config'));

        tools.logInfo('Copying license...');
        if (pkg.child) {
          tools.copy(path.join(pkg.paths.root, '..', '..', 'LICENSE'), path.join(pkg.paths.root, 'dist', 'LICENSE'));
        } else {
          tools.copy(path.join(pkg.paths.root, 'LICENSE'), path.join(pkg.paths.root, 'dist', 'LICENSE'));
        }

        tools.logInfo('Copying readme.md...');
        if (pkg.child) {
          tools.copy(path.join(pkg.paths.root, '..', '..', 'README.md'), path.join(pkg.paths.root, 'dist', 'README.md'));
        } else {
          tools.copy(path.join(pkg.paths.root, 'README.md'), path.join(pkg.paths.root, 'dist', 'README.md'));
        }
      }
    })


    // Proceed to local symlinking of package if it's considered as internal dependency (for hierarchical repo)
    .then(() => {
      if (pkg.build && pkg.build.internalDepedency) {

        return Promise.resolve()

          .then(() => {
            tools.logInfo('Internal dependency package => remove local tsconfig.build entries');

            const tsConfigBuildFile = path.join(process.cwd(), 'tsconfig.build.json');
            let tsConfigBuild = tools.getJsonFileContent(tsConfigBuildFile);

            console.log('Deleting JSON file entry : ' + tsConfigBuild.compilerOptions.paths[pkg.npmPkg]);
            delete tsConfigBuild.compilerOptions.paths[pkg.npmPkg];
            delete tsConfigBuild.compilerOptions.paths[pkg.npmPkg + '/*'];

            tools.writeJsonFileSync(tsConfigBuildFile, tsConfigBuild);
          })


          .then(() => {
            tools.logInfo('Creating symlink for package dist in node_modules');

            const nmPath = path.join(process.cwd(), 'node_modules');

            const nmPkgScopePath = path.join(nmPath, pkg.npmPkgScope);
            const nmPkgPath = path.join(nmPkgScopePath, pkg.npmPkgName);
            const pkgDistPath = path.join(pkg.paths.root, 'dist');

            return Promise.resolve()
              .then(() => {
                if (tools.isDirExists(nmPkgPath)) {
                  return tools.rimraf(nmPkgPath);
                }
              })
              .then(() => {
                if (!tools.isDirExists(nmPkgScopePath)) {
                  return tools.mkdir(nmPkgScopePath);
                }
              })
              .then(() => {
                return tools.link(pkgDistPath, nmPkgPath);
              })
              .catch((e) => {
                throw e;
              })
          })

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



    .then(() => {
      return notificationUtils.package.sendPackageMessage({
        package: pkg
      })
    })

    .then(() => {
      return auditStylesReport;
    })

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