import escapeRegExp from 'lodash/escapeRegExp';
import path from 'path';

import { transformString } from '../../Transforms';
import { FileTransform, FileTransforms, StringTransform } from '../../Transforms.types';
import { baseCmakeTransforms } from './cmakeTransforms';
import { JniLibNames } from './libraries';
import { packagesToRename } from './packagesConfig';

function pathFromPkg(pkg: string): string {
  return pkg.replace(/\./g, '/');
}

export function reactNativeTransforms(
  versionedReactNativeRoot: string,
  abiVersion: string
): FileTransforms {
  return {
    path: [],
    content: [
      // Update codegen folder to our customized folder
      {
        paths: './ReactAndroid/build.gradle',
        find: /"REACT_GENERATED_SRC_DIR=.+?",/,
        replaceWith: `"REACT_GENERATED_SRC_DIR=${versionedReactNativeRoot}",`,
      },
      // Add generated java to sourceSets
      {
        paths: './ReactAndroid/build.gradle',
        find: /(\bsrcDirs = \["src\/main\/java",.+)(\])/,
        replaceWith: `$1, "${path.join(versionedReactNativeRoot, 'codegen')}/java"$2`,
      },
      // Disable codegen plugin
      {
        paths: './ReactAndroid/build.gradle',
        find: /(\bid\("com\.facebook\.react"\)$)/m,
        replaceWith: '// $1',
      },
      {
        paths: './ReactAndroid/build.gradle',
        find: /(^react {[^]+?\n\})/m,
        replaceWith: '/* $1 */',
      },
      {
        paths: './ReactAndroid/build.gradle',
        find: /(\bpreBuild\.dependsOn\("generateCodegenArtifactsFromSchema"\))/,
        replaceWith: '// $1',
      },
      {
        paths: './ReactAndroid/build.gradle',
        find: /(externalNativeBuild\s*\{)([\s\S]*?)(\}\s)/g,
        replaceWith: (_, p1, p2, p3) =>
          [
            p1,
            transformString(
              p2,
              JniLibNames.map((lib: string) => ({
                find: new RegExp(`"${escapeRegExp(lib)}"`, 'g'),
                replaceWith: `"${lib}_${abiVersion}"`,
              }))
            ),
            p3,
          ].join(''),
      },
      ...packagesToRename.map((pkg: string) => ({
        paths: ['./ReactCommon/**/*.{java,h,cpp}', './ReactAndroid/src/main/**/*.{java,h,cpp}'],
        find: new RegExp(`${escapeRegExp(pathFromPkg(pkg))}`, 'g'),
        replaceWith: `${abiVersion}/${pathFromPkg(pkg)}`,
      })),
      ...reactNativeCmakeTransforms(abiVersion),
      {
        paths: './ReactAndroid/hermes-engine/build.gradle',
        find: 'libraryName "libhermes"',
        replaceWith: `libraryName "libhermes_${abiVersion}"`,
      },
      {
        paths: './ReactAndroid/hermes-engine/build.gradle',
        find: /(prefab {\s+libhermes)/,
        replaceWith: `$1_${abiVersion}`,
      },
      {
        paths: './ReactAndroid/hermes-engine/build.gradle',
        find: 'targets "libhermes"',
        replaceWith: `targets "libhermes_${abiVersion}"`,
      },
      ...[...JniLibNames, 'fb', 'fbjni'].map((libName) => ({
        paths: '*.java',
        find: new RegExp(`SoLoader.loadLibrary\\\("${escapeRegExp(libName)}"\\\)`),
        replaceWith: `SoLoader.loadLibrary("${libName}_${abiVersion}")`,
      })),
    ],
  };
}

export function codegenTransforms(abiVersion: string): FileTransforms {
  return {
    path: [],
    content: [
      ...packagesToRename.map((pkg: string) => ({
        paths: ['**/*.{java,h,cpp}'],
        find: new RegExp(`${escapeRegExp(pathFromPkg(pkg))}`, 'g'),
        replaceWith: `${abiVersion}/${pathFromPkg(pkg)}`,
      })),
      ...reactNativeCmakeTransforms(abiVersion),
    ],
  };
}

function reactNativeCmakeTransforms(abiVersion: string): FileTransform[] {
  const libNames = JniLibNames.map((lib: string): string =>
    lib.startsWith('lib') ? lib.slice(3) : lib
  ).filter((lib: string) => !['fbjni'].includes(lib));
  libNames.push('${HERMES_TARGET_NAME}'); // variable used in hermes-executor CMakeLists.txt
  libNames.push('hermes-engine::libhermes');

  return [
    ...baseCmakeTransforms(abiVersion, libNames).map((transform: StringTransform) => ({
      paths: 'CMakeLists.txt',
      ...transform,
    })),
    {
      paths: 'CMakeLists.txt',
      find: 'add_react_android_subdir(build/generated/source/codegen/jni)',
      replaceWith: 'add_react_android_subdir(../codegen/jni)',
    },
    {
      paths: 'CMakeLists.txt',
      find: /libhermes\.so/g,
      replaceWith: `libhermes_${abiVersion}.so`,
    },
  ];
}

export function hermesTransforms(abiVersion: string): StringTransform[] {
  return [
    {
      find: /OUTPUT_NAME hermes/g,
      replaceWith: `OUTPUT_NAME hermes_${abiVersion}`,
    },
    {
      find: /libhermes/g,
      replaceWith: `libhermes_${abiVersion}`,
    },
    {
      find: /jsi/g,
      replaceWith: `jsi_${abiVersion}`,
    },
  ];
}
