'use strict';

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

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

// ARGS
const { skipReset } = tools.getArgs();



module.exports.initRemotesConfig = () => {
  if (tools.isDirExists(path.join(process.cwd(), '.config'))) {
    return;
  }

  return Promise.resolve()
  .then(() => {
      const pkg = configUtils.packages.getPackageByNpmPkg('@csdr/remotes-config', true);

      if (!tools.isDirExists(pkg.paths.root)) {
        return cloneRemotesConfig();
      }
    })

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


const cloneRemotesConfig = module.exports.cloneRemotesConfig = () => {

  tools.logTitle('Cloning global remotes config');

  let pkg;

  return Promise.resolve()
    .then(() => {
      pkg = configUtils.packages.getPackageByNpmPkg('@csdr/remotes-config', true);

      const newPackages = [];
      newPackages.push(pkg.name);
      return configUtils.global.updateConfig({ packages: newPackages });
    })

    .then(() => {
      return gitUtils.cloneAndCheckout(pkg.repository, path.join(process.cwd(), 'packages', pkg.name), 'master');
    })

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




module.exports.generateVirtualRemote = (remoteName, cloneRemotesConfigFlag = true, standalone = false) => {
  tools.logTitle('Generating virtual remote');

  let remote, remotePath, remoteSrcPath, remoteSkeletonRootPath, remoteSkeletonPath;

  // checking if reset has to bypassed, in that case no-regeneration occurs
  if (skipReset) {
    return;
  }

  return Promise.resolve()
    // clone remotes config if first init
    .then(() => {
      if (cloneRemotesConfigFlag) {
        if (standalone) {
          return configUtils.global.cloneConfig();
        } else {
          if (tools.isDirExists(path.join(process.cwd(), '.csdr'))) {
            return cloneRemotesConfig();
          }
        }
      }
    })

    // getting remote config
    .then(() => {
      remote = configUtils.remotes.getRemote(remoteName, standalone);

      if (!remote) {
        throw new Error(`Remote ${remoteName} can't be found in the remotes CSDR configuration OR the remotes configs of the project`);
      }

      tools.logInfo('Remote config found: ')
      console.log(remote);

      remotePath = path.join(process.cwd(), 'remotes', remote.name);
      remoteSrcPath = path.join(remotePath, 'src');
      remoteSkeletonRootPath = path.join(__dirname, 'remotes', remote.euiVersion);
      remoteSkeletonPath = path.join(remoteSkeletonRootPath, 'base');
    })

    .then(() => {
      return tools.rimraf(remoteSrcPath);
    })

    .then(() => {
      // copying default base sources
      tools.logInfo(`Copying base sources => ${remoteSkeletonPath} ==> ${remotePath}`);
      tools.copy(remoteSkeletonPath, remotePath);

      if (remote.build && remote.build.esbuild) {
        tools.logInfo('Esbuild option detected, replacing angular.json esbuild config');
        tools.move(path.join(remotePath, 'angular.esbuild.json'), path.join(remotePath, 'angular.json'));
      } else {
        tools.remove(path.join(remotePath, 'angular.esbuild.json'));
      }

      // adding the dependendies files
      tools.writeJsonFileSync(path.join(remotePath, 'dependencies-composite.json'), remote.dependencies.composite);
      if (remote.dependencies.base) {
        tools.writeJsonFileSync(path.join(remotePath, 'dependencies-base.json'), remote.dependencies.base);
      }

      // standalone tsconfig replacement
      if (standalone) {
        tools.move(path.join(remotePath, 'tsconfig.app.standalone.json'), path.join(remotePath, 'tsconfig.app.json'));
      } else {
        tools.remove(path.join(remotePath, 'tsconfig.app.standalone.json'));
      }

      // adding dependencies per env
      const envs = ['INT', 'ACC', 'DLT', 'TRN', 'PPD', 'PROD'];

      envs.forEach((env) => {
        if (remote.dependencies[env]) {
          const lockedDeps = {
            lockedDependencies: remote.dependencies[env]
          };
          tools.writeJsonFileSync(path.join(remotePath, `dependencies-composite-${env}.json`), lockedDeps);
        }
      });

      // replace package.json (different extension when eUI tools published to avoid npm publish clashing)
      if (tools.isFileExists(path.join(remotePath, 'package.json_TO_REPLACE'))) {
        tools.move(path.join(remotePath, 'package.json_TO_REPLACE'), path.join(remotePath, 'package.json'));
      }

      // generating angular json
      const angularJsonPath = path.join(remotePath, 'angular.json');
      let angularJson = tools.getJsonFileContent(angularJsonPath);

      let angularContent = JSON.stringify(angularJson);
      angularContent = angularContent.replace('@remote.name@', remote.name);
      angularContent = angularContent.replace('@remote.name@', remote.name);

      // this is only applicated for v10 remotes and exclusively for SEDIA if provided, default to /mwp for MWP remotes
      if (remote.build && remote.build.deployUrlRoot) {
        angularContent = angularContent.replace('@remote.deploy.url.root@', remote.build.deployUrlRoot);
      } else {
        angularContent = angularContent.replace('@remote.deploy.url.root@', '/mwp');
      }

      angularJson = JSON.parse(angularContent);
      angularJson.projects[remote.name].architect.build.options.styles = remote.angularConfig.styles;

      if (remote.angularConfig.scripts) {
        angularJson.projects[remote.name].architect.build.options.scripts = [
          ...angularJson.projects[remote.name].architect.build.options.scripts,
          ...remote.angularConfig.scripts
        ];
      }

      tools.writeJsonFileSync(angularJsonPath, angularJson);

      tools.logSuccess('OK => angular.json generated');


      // generating package.json
      const packageJsonPath = path.join(remotePath, 'package.json');
      let packageJson = tools.getJsonFileContent(packageJsonPath);

      packageJson.name = remote.npmPkg;

      tools.writeJsonFileSync(packageJsonPath, packageJson);

      tools.logSuccess('OK => package.json generated');

      // initializing "full" remote sources
      if (remote.fullSkeletonSources) {
        const fullCommonPath = path.join(remoteSkeletonRootPath, 'full', 'common');
        const fullOptionsPath = path.join(remoteSkeletonRootPath, 'full', 'options');

        const optionUserReducersPath = path.join(fullOptionsPath, 'user-reducers');
        const optionAllLocalesPath = path.join(fullOptionsPath, 'all-locales');
        const optionExtraLocalesPath = path.join(fullOptionsPath, 'extra-locales');
        const optionParticipantPath = path.join(fullOptionsPath, 'participant');
        const optionAgGridPath = path.join(fullOptionsPath, 'ag-grid');
        const optionUserReducersDef = tools.getJsonFileContent(path.join(fullOptionsPath, 'definitions', 'user-reducers.json'));
        const optionZipkinDef = tools.getJsonFileContent(path.join(fullOptionsPath, 'definitions', 'zipkin.json'));
        const optionDynatraceDef = tools.getJsonFileContent(path.join(fullOptionsPath, 'definitions', 'dynatrace.json'));
        const optionParticipantDef = tools.getJsonFileContent(path.join(fullOptionsPath, 'definitions', 'participant.json'));
        const optionDynamicFormsDef = tools.getJsonFileContent(path.join(fullOptionsPath, 'definitions', 'dynamic-forms.json'));

        tools.logInfo(`copying full sources skeleton : ${fullCommonPath} ==> ${remoteSrcPath}`);
        tools.copy(fullCommonPath, remoteSrcPath);

        // initializing dynamic contents, filled based on options provided in config metadata
        let importsContent = [];
        let definitionsContent = [];
        let declarationsContent = [];
        let providersContent = [];
        let constructorDeclarationsContent = [];

        // ag-grid license specific main.ts
        // license token is replaced at post-install, we get it from the remote root UI pkg assets at specific location
        if (remote.skeletonConfig.aggridLicenseInjection) {
          tools.copy(optionAgGridPath, remoteSrcPath);

          const rootPkgLicensePath = path.join(
            remote.paths.repoNodeModules,
            remote.skeletonConfig.rootNpmPkg,
            'assets', 'ag-grid-license', 'license.json'
          );

          if (tools.isFileExists(rootPkgLicensePath)) {
            const licenseJSON = tools.getJsonFileContent(rootPkgLicensePath);
            const license = licenseJSON.license;
            tools.logInfo(`license key found : ${license}`);

            const mainTsPath = path.join(remote.paths.src, 'main.ts');
            console.log(`replacing in ${mainTsPath}`);
            tools.replaceInFileSync(mainTsPath, 'LICENSE_KEY_VALUE', license);

            tools.logInfo('main.ts content after replacement : ');
            const mainTsContent = tools.getFileContent(mainTsPath);
            console.log(mainTsContent);

            tools.logSuccess('OK => main.ts replaced');
          }
        }


        // extra routes
        if (remote.skeletonConfig.extraUrls) {
          let extraUrlsConfigPlaceholder = '', extraUrlsRoutesPlaceholder = '', extraUrlsImportsPlaceholder = '';
          remote.skeletonConfig.extraUrls.forEach((url) => {
            extraUrlsConfigPlaceholder += `${url.name}: '${url.path}', `;
            extraUrlsRoutesPlaceholder += `{ path: appConfig.global.${url.name}, children: ${url.import} },`;
            extraUrlsImportsPlaceholder += `${url.import},`;
          });

          tools.replaceInPath(remoteSrcPath, '// EXTRA_URLS_CONFIG_PLACEHOLDER', extraUrlsConfigPlaceholder);
          tools.replaceInPath(remoteSrcPath, '// EXTRA_URLS_ROUTES_PLACEHOLDER', extraUrlsRoutesPlaceholder);
          tools.replaceInPath(remoteSrcPath, '// EXTRA_URLS_IMPORTS_PLACEHOLDER', extraUrlsImportsPlaceholder);
        }


        // checking options

        // if no options found, we inject default modules defs
        if (!remote.skeletonConfig.options) {
          definitionsContent.push('StoreModule.forRoot(TOKEN, { metaReducers })');

        // if options, all options are checked and default modules defs are injected following certain conditions
        } else {
          const pushContent = (obj) => {
            if (obj.imports) importsContent.push(obj.imports);
            if (obj.definitions) definitionsContent.push(obj.definitions);
            if (obj.declarations) declarationsContent.push(obj.declarations);
            if (obj.providers) providersContent.push(obj.providers);
            if (obj.constructorDeclarations) constructorDeclarationsContent.push(obj.constructorDeclarations);
          }

          // user-reducers specific sources
          if (remote.skeletonConfig.options.userReducers) {
            tools.copy(optionUserReducersPath, remoteSrcPath);
            definitionsContent.push('StoreModule.forRoot(TOKEN)');
            pushContent(optionUserReducersDef);
          } else {
            definitionsContent.push('StoreModule.forRoot(TOKEN, { metaReducers })');
          }

          // all-locales specific sources
          if (remote.skeletonConfig.options.allLocales) {
            tools.copy(optionAllLocalesPath, remoteSrcPath);
          }

          // extra-locales specific sources
          if (remote.skeletonConfig.options.extraLocales) {
            tools.copy(optionExtraLocalesPath, remoteSrcPath);
          }

          // zipkin
          if (remote.skeletonConfig.options.zipkin) {
            pushContent(optionZipkinDef);
          }

          // dynatrace
          if (remote.skeletonConfig.options.dynatrace) {
            pushContent(optionDynatraceDef);
          }

          // dynamic-forms
          if (remote.skeletonConfig.options.dynamicForms) {
            pushContent(optionDynamicFormsDef);
          }

          // participant
          if (remote.skeletonConfig.options.participant) {
            tools.copy(optionParticipantPath, remoteSrcPath);
            pushContent(optionParticipantDef);

            let blockContainerPlaceholder = '';
            if (remote.skeletonConfig.blockContainerName) {
              blockContainerPlaceholder = `<${remote.skeletonConfig.blockContainerName} [block]="block"></${remote.skeletonConfig.blockContainerName}>`;
            }
            if (remote.skeletonConfig.blockContainerTypes) {
              remote.skeletonConfig.blockContainerTypes.forEach((bc) => {
                blockContainerPlaceholder += `
                <ng-container *ngIf="${bc.condition}">
                <${bc.name} [block]="block"></${bc.name}>
                </ng-container>
                `;
              });
            }
            tools.replaceInPath(remoteSrcPath, '<!-- BLOCK_CONTAINER_PLACEHOLDER -->', blockContainerPlaceholder);
          }
        }

        // replace option in module.ts placeholders
        const moduleTsPath = path.join(remoteSrcPath, 'app', 'module.ts');
        tools.replaceInFileSync(moduleTsPath, '// IMPORTS', importsContent.join('\n'));
        tools.replaceInFileSync(moduleTsPath, '// DEFINITIONS', `${definitionsContent.join() ? definitionsContent.join(',\n') + ',' : ''}`);
        tools.replaceInFileSync(moduleTsPath, '// DECLARATIONS', declarationsContent.join('\n'));
        tools.replaceInFileSync(moduleTsPath, '// PROVIDERS', providersContent.join(',\n'));
        tools.replaceInFileSync(moduleTsPath, '// CONSTRUCTOR DECLARATIONS', constructorDeclarationsContent.join('\n'));

        tools.logInfo('Replacing skeleton config tokens');
        tools.replaceInPath(remoteSrcPath, '@remote.name@', remote.name);
        tools.replaceInPath(remoteSrcPath, '@base.url@', remote.skeletonConfig.baseUrl);
        if (remote.skeletonConfig.subRouteUrl) {
          tools.replaceInPath(remoteSrcPath, '@sub.route.url@', remote.skeletonConfig.subRouteUrl);
        } else {
          tools.replaceInPath(remoteSrcPath, '@sub.route.url@', '');
        }
        tools.replaceInPath(remoteSrcPath, '@element.name@', remote.skeletonConfig.elementName);
        let storeName;
        if (remote.skeletonConfig.storeName) {
          storeName = remote.skeletonConfig.storeName;
        } else {
          storeName = remote.skeletonConfig.elementName;
        }
        tools.replaceInPath(remoteSrcPath, '@store.name@', storeName);
        tools.replaceInPath(remoteSrcPath, '@root.common.module@', remote.skeletonConfig.rootCommonModule);
        tools.replaceInPath(remoteSrcPath, '@root.npm.pkg@', remote.skeletonConfig.rootNpmPkg);


        tools.logSuccess('OK => copy done - Tokens replaced');
      }
    })


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