'use strict';

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

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

// INNER MODULES
const innerPackages = require('./packages');
const innerProjects = require('./projects');


module.exports.cloneConfig = () => {
  return Promise.resolve()
    .then(() => {
      return gitUtils.cloneRepoStandalone(
        'csdr-config',
        path.join(process.cwd(), '.config')
      );
    })

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



module.exports.getCsdrConfig = (full = true) => {
  let globalConfig, appsConfig, packagesConfig, remotesConfig;

  if (tools.isDirExists(path.join(process.cwd(), '.config'))) {
    globalConfig = require(path.join(process.cwd(), '.euirc-config.json'));
    appsConfig = require(path.join(process.cwd(), '.config', '.euirc-apps.json'));
    packagesConfig = require(path.join(process.cwd(), '.config', '.euirc-packages.json'));
    remotesConfig = require(path.join(process.cwd(), '.config', 'remotes', '.euirc-remotes.json'));

  } else {
    globalConfig = require(path.join(process.cwd(), '.csdr', '.euirc-csdr-config.json'));
    appsConfig = require(path.join(process.cwd(), '.csdr', '.euirc-csdr-apps.json'));
    packagesConfig = require(path.join(process.cwd(), '.csdr', '.euirc-csdr-packages.json'));
    remotesConfig = require(path.join(process.cwd(), '.csdr', '.euirc-csdr-remotes.json'));
  }

  const config = globalConfig;

  config.projects = {};
  config.packages = {};
  config.remotes = {};

  Object.keys(appsConfig).forEach((p) => {
    config.projects[p] = appsConfig[p];

    // checking if package has config override in its own folder
    const prjCsdrConfig = path.join(process.cwd(), 'apps', p, '.csdr-config.json');

    if (tools.isFileExists(prjCsdrConfig)) {
      const prjCsdrConfigJson = require(prjCsdrConfig);
      config.projects[p] = prjCsdrConfigJson;
    }
  })

  Object.keys(packagesConfig).forEach((p) => {
    config.packages[p] = packagesConfig[p];

    // checking if package has config override in its own folder
    const pkgCsdrConfig = path.join(process.cwd(), 'packages', p, '.csdr-config.json');

    if (tools.isFileExists(pkgCsdrConfig)) {
      const pkgCsdrConfigJson = require(pkgCsdrConfig);
      config.packages[p] = pkgCsdrConfigJson;
    }
  })

  Object.keys(remotesConfig).forEach((r) => {
    config.remotes[r] = remotesConfig[r];
  })

  if (full) {
    // flatten children packages
    Object.keys(config.packages).forEach((p) => {
      // getting package
      const pkg = config.packages[p];

      // insert children packages if any
      if (pkg && pkg.parent) {
        Object.keys(pkg.packages).forEach((pc) => {
          config.packages[pc] = pkg.packages[pc];
        })
      }
    })
  }

  return config;
}


const getGeneratedConfig = (euircBaseFile) => {
  // fetching local euirc.json config
  delete require.cache[euircBaseFile];
  let configContent = require(euircBaseFile);

  // fetching global csdr config
  const globalConfig = this.getCsdrConfig();

  // taking the global config as root
  const genConfig = { ...globalConfig };

  // initializing projects and packages objects
  genConfig.projects = {};
  genConfig.packages = {};
  genConfig.packagesBranches = [];
  genConfig.remotes = {};

  // remapping projects against csdr projects config
  configContent.projects.forEach((p) => {
    genConfig.projects[p] = globalConfig.projects[p];

    // checking if project has config override in its own folder
    const prjCsdrConfig = path.join(process.cwd(), 'apps', p, '.csdr-config.json');

    if (tools.isFileExists(prjCsdrConfig)) {
      const prjCsdrConfigJson = require(prjCsdrConfig);
      genConfig.projects[p] = prjCsdrConfigJson;
    }
  })

  // remapping projects against csdr packages config
  if (configContent.packages) {
    configContent.packages.forEach((p) => {
      genConfig.packages[p] = globalConfig.packages[p];

      // checking if package has config override in its own folder
      const pkgCsdrConfig = path.join(process.cwd(), 'packages', p, '.csdr-config.json');

      if (tools.isFileExists(pkgCsdrConfig)) {
        const pkgCsdrConfigJson = require(pkgCsdrConfig);
        genConfig.packages[p] = pkgCsdrConfigJson;
      }
    })

    // treating parent / children packages
    Object.keys(genConfig.packages).forEach((p) => {
      // getting package
      const pkg = genConfig.packages[p];

      // insert children packages if any
      if (pkg && pkg.parent) {
        Object.keys(pkg.packages).forEach((pc) => {
          genConfig.packages[pc] = pkg.packages[pc];
        })
      }
    })
  }

  // remapping remotes
  if (configContent.remotes) {
    configContent.remotes.forEach((r) => {
      genConfig.remotes[r] = globalConfig.remotes[r];
    })
  }

  // packages branches for custom initialization
  genConfig.packagesBranches = configContent.packagesBranches;

  return genConfig;
}


const getConfig = module.exports.getConfig = () => {
  let configFile;
  let isCsdr;

  if (tools.isDirExists(path.join(process.cwd(), '.csdr')) || tools.isDirExists(path.join(process.cwd(), '.config'))) {
    isCsdr = true;
    if (tools.isDirExists(path.join(process.cwd(), '.csdr'))) {
      configFile = path.join(process.cwd(), '.csdr', '.euirc.json');
    } else {
      configFile = path.join(process.cwd(), '.config', '.euirc.json');
    }
  } else {
    configFile = path.join(process.cwd(), '.euirc.json');
    isCsdr = false;
  }

  if (!tools.isFileExists(configFile)) {
    tools.logError('ERROR!!! .euirc file missing - use npm run init to generate it ');
    throw new Error('CONFIG_FILE_NOT_FOUND');
  }

  if (isCsdr) {
    return getGeneratedConfig(configFile);
  } else {
    return require(configFile);
  }
}




module.exports.updateConfig = (args = { project, projects, packages, packagesBranches, remotes, reset}) => {
  tools.logInfo('Updating euirc config');
  console.log(args);

  let configFile;

  if (tools.isDirExists(path.join(process.cwd(), '.config'))) {
    configFile = path.join(process.cwd(), '.config', '.euirc.json');
  } else {
    configFile = path.join(process.cwd(), '.csdr', '.euirc.json');
  }

  let newConfig = {};

  if (!tools.isFileExists(configFile) || args.reset) {
    newConfig.projects = [];

    if (args.projects) {
      newConfig.projects = args.projects;

    } else {
      if (args.project && args.project !== 'NONE') {
        newConfig.projects.push(args.project);
      }
      newConfig.packages = [];
      if (args.packages) {
        newConfig.packages = args.packages;
      }
      newConfig.packagesBranches = [];
      if (args.packagesBranches) {
        newConfig.packagesBranches = args.packagesBranches;
      }
      newConfig.remotes = [];
      if (args.remotes) {
        newConfig.remotes = args.remotes;
      }
    }

  } else {
    newConfig = require(configFile);

    if (args.projects) {
      newConfig.projects = args.projects;

    } else {
      if (args.project && args.project !== 'NONE') {
        if (newConfig.projects.indexOf(args.project) < 0) {
          newConfig.projects.push(args.project);
        }
      }

      if (args.packages) {
        newConfig.packages = tools.removeArrayDuplicates([...newConfig.packages || [], ...args.packages]);
      }
      if (args.packagesBranches) {
        newConfig.packagesBranches = tools.removeArrayDuplicates([...newConfig.packagesBranches || [], ...args.packagesBranches]);
      }

      if (args.remotes) {
        newConfig.remotes = tools.removeArrayDuplicates([...newConfig.remotes || [], ...args.remotes]);
      }
    }
  }

  tools.writeJsonFileSync(configFile, newConfig);
}



const getConvertedOptions = (config) => {
  let configOptions = {
    GIT_HOST_REMOTE: null,
    DEVOPS_METADATA_REPOSITORY: null,
    DEVOPS_METADATA_LOCKS_REPOSITORY: null,
    DEVOPS_METADATA_PATH: null,
    DEVOPS_METADATA_LOCKS_PATH: null,
    CSDR_REMOTES_CONFIG_REPOSITORY: null,
    CSDR_REMOTES_CONFIG_PATH: null,
    ISSUES_MANAGER_HOST: null,
    NPM_REGISTRY_DEFAULT: null,
    NPM_REGISTRY_DEFAULT_2: null,
    NPM_REGISTRY_INSTALL: null,
    NPM_FIXED_DEPENDENCIES: null,
    SONAR_HOST: null,
    NOTIFICATION_CLIENT: null,
    SLACK_HOOK: null,
    SLACK_CHANNEL_FRONTEND: null,
    SLACK_CHANNEL_BACKEND: null,
    SLACK_CHANNEL_PROJECT: null,
    MSTEAMS_HOST: null,
    MSTEAMS_FRONTEND_CHANNEL: null,
    MSTEAMS_BACKEND_CHANNEL: null,
    MSTEAMS_PROJECT_CHANNEL: null,
    MSTEAMS_CHANNELS_EMAILS: null,
    API_HOST: null,
    AUDIT_DEPENDENCIES_GATES: null,
    AUDIT_STYLES_GATES: null
  }

  // getting issues manager options
  const gitHost = config && config.git;

  if (gitHost) {
    if (gitHost.remote) {
      configOptions.GIT_HOST_REMOTE = gitHost.remote;
    }
  }


  // getting devops metadata options
  const devopsMetadata = config && config.devopsMetadata;

  if (devopsMetadata) {
    if (devopsMetadata.repository) {
      configOptions.DEVOPS_METADATA_REPOSITORY = devopsMetadata.repository;
    }
    if (devopsMetadata.folder) {
      configOptions.DEVOPS_METADATA_PATH = path.join(process.cwd(), devopsMetadata.folder);
    }
    if (devopsMetadata.locksRepository) {
      configOptions.DEVOPS_METADATA_LOCKS_REPOSITORY = devopsMetadata.locksRepository;
    }
    if (devopsMetadata.locksFolder) {
      configOptions.DEVOPS_METADATA_LOCKS_PATH = path.join(process.cwd(), devopsMetadata.locksFolder);
    }
  }

  // csdr remotes config options
  const csdrRemotesConfig = config && config.csdrRemotesConfig;

  if (csdrRemotesConfig) {
    if (csdrRemotesConfig.repository) {
      configOptions.CSDR_REMOTES_CONFIG_REPOSITORY = csdrRemotesConfig.repository;
    }

    if (csdrRemotesConfig.folder) {
      configOptions.CSDR_REMOTES_CONFIG_PATH = path.join(process.cwd(), csdrRemotesConfig.folder);
    }
  }

  // getting issues manager options
  const issuesManager = config && config.issuesManager;

  if (issuesManager) {
    if (issuesManager.host) {
      configOptions.ISSUES_MANAGER_HOST = issuesManager.host;
    }
  }

  // getting npm options
  const npm = config && config.npm;
  if (npm) {
    if (npm.registry && npm.registry.install) {
      configOptions.NPM_REGISTRY_INSTALL = npm.registry.install;
    }
    if (npm.registry && npm.registry.default) {
      configOptions.NPM_REGISTRY_DEFAULT = npm.registry.default;
    }
    if (npm.registry && npm.registry.default2) {
      configOptions.NPM_REGISTRY_DEFAULT_2 = npm.registry.default2;
    }
    if (npm.fixedDependencies) {
      configOptions.NPM_FIXED_DEPENDENCIES = npm.fixedDependencies;
    }
  }

  // getting sonar options
  const sonar = config && config.sonar;
  if (sonar) {
    if (sonar.host) {
      configOptions.SONAR_HOST = sonar.host;
    }
  }

  // getting notification options (replacing slack only above)
  const notification = config && config.notification;

  if (notification) {
    if (notification.defaultClient) {
      configOptions.NOTIFICATION_CLIENT = notification.defaultClient;
    }

    const slack = notification.slack;

    if (slack) {
      if (slack.host && slack.hookToken) {
        configOptions.SLACK_HOOK = slack.host + '/' + slack.hookToken;
      }
      if (slack.channels) {
        if (slack.channels.frontend) {
          configOptions.SLACK_CHANNEL_FRONTEND = slack.channels.frontend;
        } else {
          configOptions.SLACK_CHANNEL_FRONTEND = slack.defaultChannel;
        }

        if (slack.channels.backend) {
          configOptions.SLACK_CHANNEL_BACKEND = slack.channels.backend;
        } else {
          configOptions.SLACK_CHANNEL_BACKEND = slack.defaultChannel;
        }

        if (slack.channels.project) {
          configOptions.SLACK_CHANNEL_PROJECT = slack.channels.project;
        } else {
          configOptions.SLACK_CHANNEL_PROJECT = slack.defaultChannel;
        }
      }
    }

    const msteams = notification.msteams;

    if (msteams) {
      if (msteams.host) {
        configOptions.MSTEAMS_HOST = msteams.host;
      }

      if (msteams.channels) {
        if (msteams.channels.frontend) {
          configOptions.MSTEAMS_FRONTEND_CHANNEL = msteams.channels.frontend;
        }
        if (msteams.channels.backend) {
          configOptions.MSTEAMS_BACKEND_CHANNEL = msteams.channels.backend;
        }
        if (msteams.channels.project) {
          configOptions.MSTEAMS_PROJECT_CHANNEL = msteams.channels.project;
        }
      }

      if (msteams.channelsEmails) {
        configOptions.MSTEAMS_CHANNELS_EMAILS = msteams.channelsEmails;
      }
    }
  }

  // api options
  const api = config && config.api;
  if (api) {
    if (api.host) {
      configOptions.API_HOST = api.host;
    }
  }

  // audit options
  const audit = config && config.audit;
  if (audit) {
    if (audit.dependencies) {
      if (audit.dependencies.gates) {
        configOptions.AUDIT_DEPENDENCIES_GATES = [];
        Object.keys(audit.dependencies.gates).forEach((v) => {
          const gatesForVersion = audit.dependencies.gates[v];
          configOptions.AUDIT_DEPENDENCIES_GATES[v] = {
            "critical": gatesForVersion.critical,
            "high": gatesForVersion.high,
            "moderate": gatesForVersion.moderate
          };
        })
      }
    }

    if (audit.styles) {
      if (audit.styles.gates) {
        configOptions.AUDIT_STYLES_GATES = [];
        Object.keys(audit.styles.gates).forEach((v) => {
          const gatesForVersion = audit.styles.gates[v];
          configOptions.AUDIT_STYLES_GATES[v] = {
            "material": gatesForVersion.material,
            "primeng": gatesForVersion.primeng,
            "euiOverrides": gatesForVersion.euiOverrides,
            "sizesPxEm": gatesForVersion.sizesPxEm,
            "boxShadow": gatesForVersion.boxShadow,
            "fontFamily": gatesForVersion.fontFamily,
            "plainColors": gatesForVersion.plainColors,
            "important": gatesForVersion.important,
            "ngDeep": gatesForVersion.ngDeep,
            "zIndex": gatesForVersion.zIndex,
            "inlineStyles": gatesForVersion.inlineStyles,
            "uxCmp": gatesForVersion.uxCmp,
            "allModules": gatesForVersion.allModules,
          };
        })
      }
    }
  }

  return configOptions;
}



module.exports.getConfigOptions = () => {
  const config = this.getConfig();

  return getConvertedOptions(config);
}


module.exports.getConfigOptionsStandalone = () => {
  const config = require(path.join(process.cwd(), '.euirc-config.json'));

  return getConvertedOptions(config);
}


module.exports.getLocalEuiVersion = () => {
  let euiVersionsLocal = [
    ...innerPackages.getLocalPackagesEuiVersion(),
    ...innerProjects.getLocalProjectsEuiVersion(),
  ];
  euiVersionsLocal = tools.removeArrayDuplicates(euiVersionsLocal);

  if (euiVersionsLocal.length > 1) {
    tools.logError('Multiple versions of eUI found in local CSDR...aborting');
    tools.logError(`Ensure tha you've not installed packages that differs in versions, check the log above to identify which one is problematic`);
    console.log(euiVersionsLocal);
    throw new Error('MULTIPLE_LOCAL_EUI_VERSIONS_FOUND');

  } else {
    tools.logSuccess('eUI version checked OK');
  }

  if (euiVersionsLocal) {
    return euiVersionsLocal[0];

  } else {
    return null;
  }
}


module.exports.generateCustomConfig = (customConfig) => {
  const configFile = path.join(process.cwd(), '.csdr', '.euirc-csdr-custom.json');

  return tools.writeJsonFileSync(configFile, customConfig);
}


module.exports.getCustomConfig = () => {
  const configFile = path.join(process.cwd(), '.csdr', '.euirc-csdr-custom.json');

  delete require.cache[configFile];

  if (tools.isFileExists(configFile)) {
    return tools.getJsonFileContent(configFile) || null;
  } else {
    return null;
  }
}



const checkPipelineEnabled = (assetName, pipelineType) => {
  tools.logTitle(`Checking pipeline enabled flags for - ${pipelineType}`);
  const pipelineConfig = getConfig().pipeline;
  console.log(pipelineConfig);

  if (pipelineConfig && pipelineConfig.enabledFlags && pipelineConfig.enabledFlags[pipelineType]) {
    return;
  } else {
    if (assetName && pipelineConfig.enabledFlags.bypassPackages && pipelineConfig.enabledFlags.bypassPackages[assetName]) {
      tools.logInfo(`Package : [${assetName}] enabled bypass activated`);
      return;
    } else {
      throw new Error('GLOBAL_PIPELINE_DISABLED');
    }
  }
}

module.exports.isPipelineEnabled = (pkg) => {
  if (pkg) {
    if (pkg.backend) {
      return checkPipelineEnabled(pkg.name, 'backend');
    } else {
      return checkPipelineEnabled(pkg.name, 'frontend');
    }

  } else {
    return checkPipelineEnabled(null, 'app');
  }
}


module.exports.isSonarEnabled = () => {
    tools.logTitle(`Checking sonar enabled flag`);
    const pipelineConfig = getConfig().pipeline;
    console.log(pipelineConfig);

    if (pipelineConfig && pipelineConfig.sonarEnabled) {
      return true;
    }

    return false;
}


module.exports.isCsdr = () => {
  return tools.isDirExists(path.join(process.cwd(), '.csdr'));
}
