const fs = require('fs-extra');
const path = require('path');
const xml = require('xmldoc');
const compose = require('lodash.flowright');

const SETTINGS_PATCH_PATTERN = `include ':app'`;
const BUILD_PATCH_PATTERN = `dependencies {`;
const MAIN_ACTIVITY_IMPORT_PATTERN = `import android.app.Activity;`;
const MAIN_ACTIVITY_PACKAGE_PATTERN = `.addPackage(new MainReactPackage())`;

const readFile = (file) =>
  () => fs.readFileSync(file, 'utf8');

const writeFile = (file, content) => content ?
  fs.writeFileSync(file, content, 'utf8') :
  (c) => fs.writeFileSync(file, c, 'utf8');

const replace = (scope, pattern, patch) =>
  scope.replace(pattern, `${pattern}\n${patch}`);

module.exports = function registerNativeAndroidModule(name, dependencyConfig, projectConfig) {
  const MODULE_DIR = path.join(process.cwd(), 'node_modules', name);
  const BUILD_PATCH = `    compile project(':${name}')`;
  const SETTINGS_PATCH = `include ':${name}'\n` +
    `project(':${name}').projectDir = ` +
    `new File(rootProject.projectDir, '../node_modules/${name}/android')`;

  const config = require(path.join(MODULE_DIR, 'package.json')).rnpm;

  /**
   * Replace SETTINGS_PATCH_PATTERN by patch in the passed content
   * @param  {String} content Content of the Settings.gradle file
   * @return {String}         Patched content of Settings.gradle
   */
  const patchProjectSettings = (content) =>
    replace(content, SETTINGS_PATCH_PATTERN, SETTINGS_PATCH);

  /**
   * Replace BUILD_PATCH_PATTERN by patch in the passed content
   * @param  {String} content Content of the Build.gradle file
   * @return {String}         Patched content of Build.gradle
   */
  const patchProjectBuild = (content) =>
    replace(content, BUILD_PATCH_PATTERN, BUILD_PATCH);

  /**
   * Make a MainActivity.java program patcher
   * @param  {String}   importPath Import path, e.g. com.oblador.vectoricons.VectorIconsPackage;
   * @param  {String}   instance   Code to instance a package, e.g. new VectorIconsPackage();
   * @return {Function}            Patcher function
   */
  const makeMainActivityPatcher = (content) =>
    replace(content,
      MAIN_ACTIVITY_IMPORT_PATTERN,
      dependencyConfig.packageImportPath) &&
    replace(content,
      MAIN_ACTIVITY_PACKAGE_PATTERN,
      `                .addPackage(${dependencyConfig.packageInstance})`
    );

  const applySettingsGradlePatch = compose(
    writeFile(projectConfig.settingsGradlePath),
    patchProjectSettings,
    readFile(projectConfig.settingsGradlePath)
  );

  const applyBuildGradlePatch = compose(
    writeFile(projectConfig.buildGradlePath),
    patchProjectBuild,
    readFile(projectConfig.buildGradlePath)
  );

  const applyMainActivityPatch = compose(
    writeFile(projectConfig.mainActivityPath),
    makeMainActivityPatcher,
    readFile(projectConfig.mainActivityPath)
  );

  compose(
    applySettingsGradlePatch,
    applyBuildGradlePatch,
    applyMainActivityPatch
  )();
};

@@ -1743,30 +1743,139 @@
 LD_PATCH);%0A%0A
+  const getMainActivityPatch = () =%3E%0A    %60                .addPackage($%7BdependencyConfig.packageInstance%7D)%60%0A%0A
   /**%0A
-
    * Make a 
@@ -2318,38 +2318,32 @@
 replace(content,
-%0A     
  MAIN_ACTIVITY_P
@@ -2361,86 +2361,31 @@
 ERN,
-%0A      %60                .addPackage($%7BdependencyConfig.packageInstance%7D)%60%0A    
+ getMainActivityPatch()
 );%0A%0A
@@ -2889,23 +2889,196 @@
 );%0A%0A  co
-mpose(%0A
+nst isInstalled = compose(%0A    (content) =%3E ~content.indexOf(getMainActivityPatch()),%0A    readFile(projectConfig.mainActivityPath)%0A  );%0A%0A  if (!isInstalled(name)) %7B%0A    compose(%0A  
     appl
@@ -3091,32 +3091,34 @@
 ngsGradlePatch,%0A
+  
     applyBuildGr
@@ -3128,24 +3128,26 @@
 ePatch,%0A    
+  
 applyMainAct
@@ -3163,12 +3163,18 @@
 h%0A  
+ 
+ 
 )();%0A
+  %7D%0A
 %7D;%0A

Check if module has been linked already