#!/bin/bash
# Copyright (c) 2026 Huawei Technologies Co., Ltd.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.


if [ -z "$DEVECO_SDK_HOME" ]; then
  echo "Environment variable DEVECO_SDK_HOME is not defined"
  exit 1
fi

ENABLE_DEBUGGER=${HERMES_ENABLE_DEBUGGER:-false}
HERMES_V1_ENABLED=${HERMES_V1_ENABLED:-true}

HERMES_REPO_URL="https://github.com/facebook/hermes.git"

# NOTE: these variables should be kept in sync with the React Native version RNOH is based off of
REACT_NATIVE_VERSION="0.84.1"
HERMES_TAG="hermes-v0.15.1"
HERMES_V1_BRANCH="250829098.0.0-stable"
HERMES_V1_COMMIT="7f41c52586c320ef8341fa3a7ba10c6c3212bc6f"
HERMES_V1_VERSION="250829098.0.9"


SCRIPT_PATH=$(realpath "$0")
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
THIRD_PARTY_DIR="$SCRIPT_DIR/../../tester/harmony/react_native_openharmony/src/main/cpp/third-party"
OUTPUT_DIR="$SCRIPT_DIR/out"
HERMES_SRC_DIR="$OUTPUT_DIR/hermes"

HERMES_RELEASE_VERSION="for RN $REACT_NATIVE_VERSION"

if [ -d "$HERMES_SRC_DIR" ]; then
  echo "Removing existing Hermes sources at $HERMES_SRC_DIR"
  rm -rf "$HERMES_SRC_DIR"
fi

# clone hermes repository
echo "Cloning hermes"
if [ "$HERMES_V1_ENABLED" = "true" ]; then
  HERMES_RELEASE_VERSION="$HERMES_V1_VERSION"
  git clone --branch "$HERMES_V1_BRANCH" --single-branch "$HERMES_REPO_URL" "$HERMES_SRC_DIR"
  if [ -n "$HERMES_V1_COMMIT" ]; then
    (cd "$HERMES_SRC_DIR" && git checkout "$HERMES_V1_COMMIT")
  fi
else
  git clone -b "$HERMES_TAG" --depth 1 "$HERMES_REPO_URL" "$HERMES_SRC_DIR"
fi
# apply patch
echo
echo "Applying CMakeLists.txt patch to hermes"
if [ "$HERMES_V1_ENABLED" = "true" ]; then
  (cd "$HERMES_SRC_DIR" && git apply "$SCRIPT_DIR/hermesv1_cmakelists.patch")
else
  (cd "$HERMES_SRC_DIR" && git apply "$SCRIPT_DIR/hermes_cmakelists.patch")
fi
if [ $? -ne 0 ]; then
  echo "FAILED to apply patch."
  echo "Fix the CMakeLists.txt file yourself and generate a new patch for this version of hermes before running the build script again."
  echo "See the 'git apply' output for details"
  exit 1
fi
echo

if [ "$HERMES_V1_ENABLED" = "true" ]; then
  # Hermes V1 fails to build on 32-bit (inline asm constraint '=t'); skip armeabi-v7a.
  ARCHITECTURES=("arm64-v8a" "x86_64")
else
  ARCHITECTURES=("armeabi-v7a" "arm64-v8a" "x86_64")
fi
OHOS_SDK_NATIVE_DIR=$DEVECO_SDK_HOME/default/openharmony/native
BUILD_HERMESC_DIR=$OUTPUT_DIR/hermesc
JSI_DIR=$(realpath "$THIRD_PARTY_DIR/rn/ReactCommon/jsi")

# hermes compiler
echo "############# ENABLE_DEBUGGER ${ENABLE_DEBUGGER}"
# Set CMake build type flags based on ENABLE_DEBUGGER
if [ "$ENABLE_DEBUGGER" = "true" ]; then
  CMAKE_BUILD_TYPE_FLAG="Release"
  BUILD_TYPE_FLAG="debug" # to save lib
  HERMES_ENABLE_DEBUGGER=True
  CFLAGS="-g"
  CXXFLAGS="-g"
else
  BUILD_TYPE_FLAG="release"
  CMAKE_BUILD_TYPE_FLAG="MinSizeRel"
  HERMES_ENABLE_DEBUGGER=False
  CFLAGS="-O3 -DNDEBUG"
  CXXFLAGS="-O3 -DNDEBUG"
fi

$OHOS_SDK_NATIVE_DIR/build-tools/cmake/bin/cmake \
  -S$HERMES_SRC_DIR \
  -B$BUILD_HERMESC_DIR \
  -DJSI_DIR=$JSI_DIR \
  -DCMAKE_BUILD_TYPE=Release

$OHOS_SDK_NATIVE_DIR/build-tools/cmake/bin/cmake \
  --build $BUILD_HERMESC_DIR \
  --target hermesc -j 4

for ARCHITECTURE in "${ARCHITECTURES[@]}"; do
  echo "Building Hermes@$ARCHITECTURE"

  BUILD_TARGET_DIRECTORY="$OUTPUT_DIR/${BUILD_TYPE_FLAG}/${ARCHITECTURE}-output"
  BUILD_LIBRARY_DIRECTORY="$OUTPUT_DIR/${BUILD_TYPE_FLAG}/${ARCHITECTURE}-lib"

  # hermes engine
  $OHOS_SDK_NATIVE_DIR/build-tools/cmake/bin/cmake \
    -H$HERMES_SRC_DIR \
    -B$BUILD_TARGET_DIRECTORY \
    -GNinja \
    -DCMAKE_SYSTEM_NAME=OHOS \
    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
    -DCMAKE_SYSTEM_VERSION=1 \
    -DOHOS_ARCH=$ARCHITECTURE \
    -DOHOS_STL=c++_shared \
    -DCMAKE_TOOLCHAIN_FILE=$OHOS_SDK_NATIVE_DIR/build/cmake/ohos.toolchain.cmake \
    -DCMAKE_MAKE_PROGRAM=$OHOS_SDK_NATIVE_DIR/build-tools/cmake/bin/ninja \
    -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=$BUILD_LIBRARY_DIRECTORY \
    -DIMPORT_HOST_COMPILERS=$BUILD_HERMESC_DIR/ImportHostCompilers.cmake \
    -DJSI_DIR=$JSI_DIR \
    -DHERMES_IS_ANDROID=True \
    -DHERMES_SLOW_DEBUG=False \
    -DHERMES_BUILD_SHARED_JSI=True \
    -DHERMES_RELEASE_VERSION="$HERMES_RELEASE_VERSION" \
    -DHERMES_ENABLE_INTL=False \
    -DHERMES_ENABLE_DEBUGGER=${HERMES_ENABLE_DEBUGGER} \
    -DCMAKE_BUILD_WITH_INSTALL_RPATH=On \
    -DHERMES_ENABLE_TEST_SUITE=False \
    -DHERMES_UNICODE_LITE=True \
    -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE_FLAG} \
    -DCMAKE_C_FLAGS="${CFLAGS}" \
    -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \
    -DCMAKE_SHARED_LINKER_FLAGS_RELEASE="-Wl,--build-id" \
    -DHERMESVM_HEAP_HV_MODE=HEAP_HV_PREFER32
  if [ $? -ne 0 ]; then
    echo "FAILED to configure Hermes@$ARCHITECTURE."
    exit 1
  fi

  $OHOS_SDK_NATIVE_DIR/build-tools/cmake/bin/ninja \
    -C \
    $BUILD_TARGET_DIRECTORY \
    hermesvm
  if [ $? -ne 0 ]; then
    echo "FAILED to build Hermes@$ARCHITECTURE."
    exit 1
  fi
done

# Function to strip debug symbols and separate debug info
strip_and_separate_debug() {
  local INPUT_FILE="$1"
  local OUTPUT_DIR="$2"
  local BASENAME=$(basename "$INPUT_FILE")

  if [ ! -f "$INPUT_FILE" ]; then
    echo "Warning: $INPUT_FILE not found, skipping strip"
    return 1
  fi

  # Extract debug symbols
  echo "Extracting debug symbols from $BASENAME..."
  local OBJ_COPY=llvm-objcopy # $OHOS_SDK_NATIVE_DIR/llvm/bin/llvm-objcopy
  if command -v $OHOS_SDK_NATIVE_DIR/llvm/bin/llvm-objcopy &> /dev/null; then
    OBJ_COPY=$OHOS_SDK_NATIVE_DIR/llvm/bin/llvm-objcopy
  elif command -v objcopy &> /dev/null; then
    OBJ_COPY=objcopy
  else
    echo "Warning: Neither llvm-objcopy nor objcopy found, skipping debug extraction"
    exit 1
  fi

  $OBJ_COPY --only-keep-debug "$INPUT_FILE" "$OUTPUT_DIR/${BASENAME}.sym"

  # Create .sym.txt with build info
  local SYM_TXT_NAME="$OUTPUT_DIR/${BASENAME}.debug.txt"
  echo "Build ID: $(readelf -n "$INPUT_FILE" 2>/dev/null | grep 'Build ID' | head -1)" > $SYM_TXT_NAME
  echo "Architecture: $ARCHITECTURE" >> $SYM_TXT_NAME
  echo "Build Type: $BUILD_TYPE_FLAG" >> $SYM_TXT_NAME
  echo "Timestamp: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $SYM_TXT_NAME

  # strip debug symbols
  $OBJ_COPY --strip-debug "$INPUT_FILE"

  # Add debug link to binary
  $OBJ_COPY --add-gnu-debuglink="$OUTPUT_DIR/${BASENAME}.sym" "$INPUT_FILE"
  
  echo "Debug symbols separated to: $OUTPUT_DIR/${BASENAME}.sym"
  echo "Debug info file: $SYM_TXT_NAME"

  return 0
}

for ARCHITECTURE in "${ARCHITECTURES[@]}"; do
  mkdir -p "$THIRD_PARTY_DIR/prebuilt/${BUILD_TYPE_FLAG}/$ARCHITECTURE"
  if [ "$HERMES_V1_ENABLED" = "true" ]; then
    INPUT_SO="$OUTPUT_DIR/${BUILD_TYPE_FLAG}/${ARCHITECTURE}-lib/libhermesvm.so"
  else
    INPUT_SO="$OUTPUT_DIR/${BUILD_TYPE_FLAG}/${ARCHITECTURE}-output/lib/libhermesvm.so"
  fi
  OUTPUT_DIR_PREBUILT="$THIRD_PARTY_DIR/prebuilt/${BUILD_TYPE_FLAG}/$ARCHITECTURE"
  echo "Copying $INPUT_SO to $OUTPUT_DIR_PREBUILT/libhermesvm.so"
  # Separate debug symbols for release builds
  echo ""
  echo "Separating debug symbols for release build..."
  strip_and_separate_debug "$INPUT_SO" "$OUTPUT_DIR_PREBUILT"
  cp -f "$INPUT_SO" "$OUTPUT_DIR_PREBUILT/libhermesvm.so"
  echo "Done: $ARCHITECTURE"
  echo ""
done