#!/usr/bin/env bash

# Copyright (c) 2026 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail

RETRY_MAX_ATTEMPTS="${RETRY_MAX_ATTEMPTS:-3}"
RETRY_DELAY_SECONDS="${RETRY_DELAY_SECONDS:-10}"
DEPLOY_VERSION="${DEPLOY_VERSION:-0.150.1-0.1.0-01}"
DEPLOY_RELEASE="${DEPLOY_RELEASE:-true}"
PUBLISH_REPOSITORY="${PUBLISH_REPOSITORY:-MavenLocal}"
PUBLISH_MODE="default"
# region Ohos
SKIA_TAG="m150-1f14f1166a"
# endregion

case "$PUBLISH_REPOSITORY" in
  MavenLocal)
    PUBLISH_TASK_SUFFIX="ToMavenLocal"
    ;;
  ComposeRepo)
    PUBLISH_TASK_SUFFIX="ToComposeRepoRepository"
    ;;
  *)
    echo "[build-ohos] ERROR: unsupported PUBLISH_REPOSITORY: $PUBLISH_REPOSITORY"
    echo "[build-ohos] Supported repositories: MavenLocal, ComposeRepo"
    exit 1
    ;;
esac

PUBLISH_OHOS_ARM64_TASK=":skiko:publishOhosArm64Publication${PUBLISH_TASK_SUFFIX}"
PUBLISH_OHOS_X64_TASK=":skiko:publishOhosX64Publication${PUBLISH_TASK_SUFFIX}"
PUBLISH_KMP_TASK=":skiko:publishKotlinMultiplatformPublication${PUBLISH_TASK_SUFFIX}"

if [ $# -gt 1 ]; then
  echo "[build-ohos] ERROR: too many arguments."
  echo "[build-ohos] Usage: $0 [--skia|--fusionRenderer]"
  exit 1
fi

if [ $# -eq 1 ]; then
  case "$1" in
    --skia)
      PUBLISH_MODE="skia"
      ;;
    --fusionRenderer)
      PUBLISH_MODE="fusionRenderer"
      ;;
    *)
      echo "[build-ohos] ERROR: unsupported argument: $1"
      echo "[build-ohos] Usage: $0 [--skia|--fusionRenderer]"
      exit 1
      ;;
  esac
fi

if [ -z "${JAVA_HOME:-}" ] || [ ! -x "$JAVA_HOME/bin/java" ]; then
 echo "[build-ohos] ERROR: JAVA_HOME is not set to a valid JDK."
 echo "[build-ohos] Configure JAVA_HOME in the shell or pass it when invoking this script."
 exit 1
fi
export JAVA_HOME
export PATH="$JAVA_HOME/bin:$PATH"
echo "[build-ohos] Using JAVA_HOME: $JAVA_HOME"
java -version 2>&1 | sed -n '1p'

# 切换到项目根目录，支持从任意路径调用（如 CI 流水线）
SCRIPT_PATH="${BASH_SOURCE[0]:-$0}"
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT"

OHOS_NATIVE_DIR="${OHOS_NATIVE_DIR:-/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/native}"
export OHOS_LLVM="${OHOS_LLVM:-$OHOS_NATIVE_DIR/llvm}"
export OHOS_SYSROOT="${OHOS_SYSROOT:-$OHOS_NATIVE_DIR/sysroot}"
if [ ! -d "$OHOS_LLVM" ] || [ ! -d "$OHOS_SYSROOT" ]; then
  echo "[build-ohos] ERROR: OHOS native toolchain not found: $OHOS_NATIVE_DIR"
  exit 1
fi
echo "[build-ohos] OHOS native SDK: $OHOS_NATIVE_DIR"

# region Ohos
# Prepares the patched m150 checkout when no external checkout is supplied.
# Building is delegated to the upstream Gradle task.
prepare_ohos_skia() {
  local managed_skia_dir arm64_archive x64_archive

  if [ -n "${SKIA_DIR:-}" ]; then
    if [ ! -d "$SKIA_DIR/.git" ]; then
      echo "[build-ohos] ERROR: SKIA_DIR is not a Git checkout: $SKIA_DIR"
      return 1
    fi
    managed_skia_dir="$SKIA_DIR"
  else
    managed_skia_dir="$PROJECT_ROOT/dependencies/skia/$SKIA_TAG"
    if [ ! -d "$managed_skia_dir/.git" ]; then
      if [ -e "$managed_skia_dir" ]; then
        echo "[build-ohos] ERROR: managed Skia path exists but is not a Git checkout: $managed_skia_dir"
        return 1
      fi
      mkdir -p "$(dirname "$managed_skia_dir")"
      echo "[build-ohos] Cloning official Skia $SKIA_TAG"
      git clone --depth 1 --branch "$SKIA_TAG" https://github.com/JetBrains/skia.git "$managed_skia_dir"
    fi
  fi

  "$PROJECT_ROOT/skia/apply_patch.sh" "$managed_skia_dir"
  export OHOS_SDK_HOME="${OHOS_SDK_HOME:-$(dirname "$OHOS_NATIVE_DIR")}"

  arm64_archive="$managed_skia_dir/Skia-$SKIA_TAG-ohos-Release-arm64.zip"
  x64_archive="$managed_skia_dir/Skia-$SKIA_TAG-ohos-Release-x64.zip"
  if [ ! -f "$arm64_archive" ] || [ ! -f "$x64_archive" ]; then
    echo "[build-ohos] Building Skia $SKIA_TAG through prepareLocalSkiaBuild"
    SKIA_TARGET=ohos SKIA_VERSION="$SKIA_TAG" \
      ./gradlew :skiko:prepareLocalSkiaBuild \
        -Pskia.repo.dir="$managed_skia_dir" \
        -Pskiko.awt.enabled=false \
        -Pskiko.native.ohos.enabled=true
  fi

  SKIA_DIR="$managed_skia_dir"
  export SKIA_DIR
  echo "[build-ohos] Skia source: $SKIA_DIR"
}
# endregion

# fusionRenderer requires the fusion-render repository root (the directory containing OHRender/).
# Keep the legacy lookup order: OHRENDER_DIR, then the sibling fusion-render checkout.
if [ -z "${OHRENDER_DIR:-}" ]; then
  OHRENDER_DIR="$(cd "$(dirname "$PROJECT_ROOT")" && pwd)/fusion-render"
fi
export OHRENDER_DIR
echo "[build-ohos] OHRENDER_DIR: $OHRENDER_DIR"
echo "[build-ohos] Publish repository: $PUBLISH_REPOSITORY"

# 避免 CI 未注入 BUILD_LOG 时导致 tee 空路径报错
BUILD_LOG="${BUILD_LOG:-$PROJECT_ROOT/build-ohos.log}"
mkdir -p "$(dirname "$BUILD_LOG")"

resolve_android_sdk() {
 local default_sdk

 if [ -n "${ANDROID_HOME:-}" ] && [ -d "${ANDROID_HOME}" ]; then
   echo "${ANDROID_HOME}"
   return 0
 fi

 if [ -n "${ANDROID_SDK_ROOT:-}" ] && [ -d "${ANDROID_SDK_ROOT}" ]; then
   echo "${ANDROID_SDK_ROOT}"
   return 0
 fi

 default_sdk="${HOME:-}/Library/Android/sdk"
 if [ -n "${HOME:-}" ] && [ -d "$default_sdk" ]; then
   echo "$default_sdk"
   return 0
 fi

 return 1
}

ensure_android_local_properties() {
 local sdk_path local_props tmp_file sdk_escaped input_file
 if ! sdk_path="$(resolve_android_sdk)"; then
   echo "[build-ohos] ERROR: Android SDK not found."
   echo "[build-ohos] Please install Android SDK to: ${HOME:-<your_home>}/Library/Android/sdk"
   echo "[build-ohos] Or set ANDROID_HOME / ANDROID_SDK_ROOT manually."
   return 1
 fi

 export ANDROID_HOME="$sdk_path"
 export ANDROID_SDK_ROOT="$sdk_path"
 local_props="$PROJECT_ROOT/skiko/local.properties"
 mkdir -p "$(dirname "$local_props")"
 tmp_file="$(mktemp)"
 sdk_escaped="$(printf '%s' "$sdk_path" | sed 's/:/\\:/g')"
 input_file="$local_props"
 [ -f "$local_props" ] || input_file="/dev/null"

 awk -v sdk="$sdk_escaped" '
   BEGIN { updated = 0 }
   /^sdk\.dir=/ {
     print "sdk.dir=" sdk
     updated = 1
     next
   }
   { print }
   END {
     if (!updated) {
       print "sdk.dir=" sdk
     }
   }
 ' "$input_file" > "$tmp_file"

 mv "$tmp_file" "$local_props"
 echo "[build-ohos] Android SDK: $sdk_path"
 echo "[build-ohos] Ensured local.properties: $local_props"
}

# 默认沿用用户本机 Gradle 缓存（通常是 ~/.gradle），避免每次冷启动拉依赖。
# 仅在外部显式传入 GRADLE_USER_HOME 时使用自定义目录。
if [ -n "${GRADLE_USER_HOME:-}" ]; then
  mkdir -p "$GRADLE_USER_HOME"
fi

# skiko/settings.gradle.kts 的 buildscript 默认会访问 JetBrains Space；内网或 Space 503 时改为跳过，
# 依赖需来自 Nexus、~/.m2 或 skiko/gradle/local-buildscript-m2（见 skiko/gradle.properties 注释）。
export SKIKO_BUILDSCRIPT_SKIP_JETBRAINS_SPACE="${SKIKO_BUILDSCRIPT_SKIP_JETBRAINS_SPACE:-true}"

# 增大 Gradle 访问仓库超时，降低网络抖动导致的误失败
GRADLE_NETWORK_OPTS="-Dorg.gradle.internal.http.connectionTimeout=${GRADLE_CONNECTION_TIMEOUT_MS:-60000} -Dorg.gradle.internal.http.socketTimeout=${GRADLE_SOCKET_TIMEOUT_MS:-120000}"
export GRADLE_OPTS="${GRADLE_OPTS:-} $GRADLE_NETWORK_OPTS"

is_dependency_download_error() {
 local log_file="$1"
 grep -Eiq \
   'Could not resolve|Could not GET|Could not HEAD|Read timed out|Connection reset|Connection timed out|Temporary failure|503 Service Unavailable|502 Bad Gateway|Failed to fetch|ArtifactResolveException|Could not download' \
   "$log_file"
}

run_publish_scheme() {
 echo "[build-ohos] Pass 1/2: OHOS Skia"
 prepare_ohos_skia || return 1
 ensure_android_local_properties || return 1
 if ! ./gradlew \
   "$PUBLISH_OHOS_ARM64_TASK" \
   "$PUBLISH_OHOS_X64_TASK" \
   "$PUBLISH_KMP_TASK" \
   -x :skiko:compileCommonMainKotlinMetadata \
   -x :skiko:compileNativeJsMainKotlinMetadata \
   -x :skiko:compileNativeMainKotlinMetadata \
   -Pskiko.awt.enabled=false \
   -Pskiko.android.enabled=true \
   -Pskiko.js.enabled=false \
   -Pskiko.wasm.enabled=false \
   -Pskiko.native.enabled=false \
   -Pskiko.native.mac.enabled=false \
   -Pskiko.native.ios.enabled=false \
   -Pskiko.native.ios.arm64.enabled=true \
   -Pskiko.native.ios.simulatorArm64.enabled=true \
   -Pskiko.native.ios.x64.enabled=false \
   -Pskiko.native.ohos.enabled=true \
   -Pskiko.native.ohos.arm64.enabled=true \
   -Pskiko.native.ohos.x64.enabled=true \
   -Pskiko.upstream.redirect.enabled=true \
   -Pkotlin.stdlib.default.dependency=false \
   -Pskia.dir="$SKIA_DIR" \
   -Pdeploy.version="$DEPLOY_VERSION" \
   -Pdeploy.release="$DEPLOY_RELEASE" \
   --no-build-cache --rerun-tasks; then
   return 1
 fi

 echo "[build-ohos] Pass 2/2: OHOS fusionRenderer"
 if ! ./gradlew \
   "$PUBLISH_OHOS_ARM64_TASK" \
   "$PUBLISH_OHOS_X64_TASK" \
   -Pskiko.awt.enabled=false \
   -Pskiko.android.enabled=false \
   -Pskiko.js.enabled=false \
   -Pskiko.wasm.enabled=false \
   -Pskiko.native.enabled=false \
   -Pskiko.native.mac.enabled=false \
   -Pskiko.native.ios.enabled=false \
   -Pskiko.native.ohos.enabled=true \
   -Pskiko.native.ohos.arm64.enabled=true \
   -Pskiko.native.ohos.x64.enabled=true \
   -Pskiko.native.ohos.fusionRenderer.enabled=true \
   -Pohrender.dir="$OHRENDER_DIR" \
   -Pdeploy.version="$DEPLOY_VERSION" \
   -Pdeploy.release="$DEPLOY_RELEASE" \
   --no-build-cache --rerun-tasks; then
   return 1
 fi
}

run_publish_skia_only() {
 echo "[build-ohos] Mode: --skia (OHOS Skia)"
 prepare_ohos_skia || return 1
 ensure_android_local_properties || return 1
 ./gradlew \
   "$PUBLISH_OHOS_ARM64_TASK" \
   "$PUBLISH_OHOS_X64_TASK" \
   "$PUBLISH_KMP_TASK" \
   -x :skiko:compileCommonMainKotlinMetadata \
   -x :skiko:compileNativeJsMainKotlinMetadata \
   -x :skiko:compileNativeMainKotlinMetadata \
   -Pskiko.awt.enabled=false \
   -Pskiko.android.enabled=true \
   -Pskiko.js.enabled=false \
   -Pskiko.wasm.enabled=false \
   -Pskiko.native.enabled=false \
   -Pskiko.native.mac.enabled=false \
   -Pskiko.native.ios.enabled=false \
   -Pskiko.native.ios.arm64.enabled=true \
   -Pskiko.native.ios.simulatorArm64.enabled=true \
   -Pskiko.native.ios.x64.enabled=false \
   -Pskiko.native.ohos.enabled=true \
   -Pskiko.native.ohos.arm64.enabled=true \
   -Pskiko.native.ohos.x64.enabled=true \
   -Pskiko.upstream.redirect.enabled=true \
   -Pkotlin.stdlib.default.dependency=false \
   -Pskia.dir="$SKIA_DIR" \
   -Pdeploy.version="$DEPLOY_VERSION" \
   -Pdeploy.release="$DEPLOY_RELEASE" \
   --no-build-cache --rerun-tasks
}

run_publish_fusion_renderer_only() {
 echo "[build-ohos] Mode: --fusionRenderer (OHOS fusionRenderer)"
 ./gradlew \
   "$PUBLISH_OHOS_ARM64_TASK" \
   "$PUBLISH_OHOS_X64_TASK" \
   -Pskiko.awt.enabled=false \
   -Pskiko.android.enabled=false \
   -Pskiko.js.enabled=false \
   -Pskiko.wasm.enabled=false \
   -Pskiko.native.enabled=false \
   -Pskiko.native.mac.enabled=false \
   -Pskiko.native.ios.enabled=false \
   -Pskiko.native.ohos.enabled=true \
   -Pskiko.native.ohos.arm64.enabled=true \
   -Pskiko.native.ohos.x64.enabled=true \
   -Pskiko.native.ohos.fusionRenderer.enabled=true \
   -Pohrender.dir="$OHRENDER_DIR" \
   -Pdeploy.version="$DEPLOY_VERSION" \
   -Pdeploy.release="$DEPLOY_RELEASE" \
   --no-build-cache --rerun-tasks
}

run_with_dependency_retry() {
 local attempt=1
 local max_attempts delay attempt_log
 max_attempts="$RETRY_MAX_ATTEMPTS"
 delay="$RETRY_DELAY_SECONDS"

 while [ "$attempt" -le "$max_attempts" ]; do
   attempt_log="$(mktemp)"
  echo "[build-ohos] publish attempt ${attempt}/${max_attempts} (mode=${PUBLISH_MODE})"

  if (
    case "$PUBLISH_MODE" in
      skia)
        run_publish_skia_only
        ;;
      fusionRenderer)
        run_publish_fusion_renderer_only
        ;;
      *)
        run_publish_scheme
        ;;
    esac
  ) 2>&1 | tee "$BUILD_LOG" "$attempt_log"; then
     rm -f "$attempt_log"
     return 0
   fi

   if [ "$attempt" -lt "$max_attempts" ] && is_dependency_download_error "$attempt_log"; then
     echo "[build-ohos] 依赖下载疑似失败，${delay}s 后重试..."
     rm -f "$attempt_log"
     sleep "$delay"
     attempt=$((attempt + 1))
     continue
   fi

   rm -f "$attempt_log"
   return 1
 done
}

if run_with_dependency_retry; then
 exit 0
fi

echo "[build-ohos] 构建失败。"
exit 1
