#!/bin/bash
#
# Eazytec is pleased to support the open source community by making CPF-KMP-CMP available.
# Copyright (C) 2026 Eazytec. All rights reserved.
#
# 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 -e

# Record script start time
START_TIME=$(date +%s)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

# ====================== [1. Default Configuration and Parameter Parsing] ======================
DEFAULT_PLATFORM="ohosArm64"
DEFAULT_TARGET_ID="127.0.0.1:5555"
DEFAULT_BUNDLE_NAME="com.example.harmonyapp"
DEFAULT_ABILITY_NAME="EntryAbility"
LOCAL_OHOS_PATH=""

usage() {
    echo "Usage: $0 [options] [PLATFORM] [TARGET_ID]"
    echo ""
    echo "Parameters:"
    echo "  PLATFORM      Build platform (default: $DEFAULT_PLATFORM)"
    echo "  TARGET_ID     Device ID (default: $DEFAULT_TARGET_ID)"
    echo ""
    echo "Options:"
    echo "  -M MODES      Build set: debug | release | all（不传 -M/-m 时在终端用 1/2/3 选；非终端或 RUNOHOS_NO_MENU=1 则默认 debug）"
    echo "  -m MODE       仅 debug 或 release；与 -M 二选一，传了 -m 则不再弹出菜单"
    echo "  -b BUNDLE     Set bundle name (current: $DEFAULT_BUNDLE_NAME)"
    echo "  -a ABILITY    Set Ability name (current: $DEFAULT_ABILITY_NAME)"
    echo "  -d MODE       Debug mode: debug or attach (default: attach)"
    echo "  -p PATH       Set external OHOS project path (localOhosPath)"
    echo "  -h            Show this help message"
    echo ""
    echo "Examples:"
    echo "  $0 ohosArm64 127.0.0.1:5555"
    echo "  $0 -M all                      # debug then release on same device"
    echo "  $0 -M release                  # release only"
    echo "  $0 -m release                  # release only (shorthand)"
    echo "  $0 -b com.test.app -a MainAbility"
    echo "  $0 -p /path/to/external/ohos/project"
    exit 0
}

# Preset variables
BUNDLE_NAME=$DEFAULT_BUNDLE_NAME
ABILITY_NAME=$DEFAULT_ABILITY_NAME
BUILD_MODE="debug"
BUILD_MODES_SELECT=""
M_EXPLICIT=0
m_EXPLICIT=0
DEBUG_MODE="attach"
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'   # No Color
# Parse options (supports options in any position, e.g. ohosArm64 62Q0226107024702 -m release)
POSITIONALS=()
while [[ $# -gt 0 ]]; do
    case $1 in
        -M) M_EXPLICIT=1; BUILD_MODES_SELECT="$2"; shift 2 ;;
        -m) m_EXPLICIT=1; BUILD_MODE="$2"; shift 2 ;;
        -b) BUNDLE_NAME="$2"; shift 2 ;;
        -a) ABILITY_NAME="$2"; shift 2 ;;
        -d) DEBUG_MODE="$2"; shift 2 ;;
        -p) LOCAL_OHOS_PATH="$2"; shift 2 ;;
        -h) usage ;;
        -*)
            echo "Unknown option: $1"
            usage
            ;;
        *)
            POSITIONALS+=("$1")
            shift
            ;;
    esac
done

PLATFORM=${POSITIONALS[0]:-$DEFAULT_PLATFORM}
TARGET_ID=${POSITIONALS[1]:-$DEFAULT_TARGET_ID}

pick_rundebug_build_modes() {
    if [[ -n "${RUNOHOS_NO_MENU:-}" ]]; then
        BUILD_MODES_SELECT="debug"
        return
    fi
    if [[ ! -t 0 ]]; then
        BUILD_MODES_SELECT="debug"
        return
    fi
    echo ""
    echo "请选择构建类型（输入数字后回车）:"
    echo "  1) 仅 debug"
    echo "  2) 仅 release"
    echo "  3) debug + release（先后各跑一轮）"
    local _c
    read -r -p "请输入 1 / 2 / 3 [默认 1]: " _c || true
    _c=${_c:-1}
    case "$_c" in
        1) BUILD_MODES_SELECT=debug ;;
        2) BUILD_MODES_SELECT=release ;;
        3) BUILD_MODES_SELECT=all ;;
        *) echo "无效输入，使用默认 1（debug）"; BUILD_MODES_SELECT=debug ;;
    esac
}

if [[ "$M_EXPLICIT" -eq 1 ]]; then
    :
elif [[ "$m_EXPLICIT" -eq 1 ]]; then
    BUILD_MODES_SELECT="$BUILD_MODE"
else
    pick_rundebug_build_modes
fi

case "$(echo "$BUILD_MODES_SELECT" | tr '[:upper:]' '[:lower:]')" in
    debug)   BUILD_MODES=(debug) ;;
    release) BUILD_MODES=(release) ;;
    all)     BUILD_MODES=(debug release) ;;
    *)
        echo "Error: -M must be debug, release, or all (got: $BUILD_MODES_SELECT)"
        exit 2
        ;;
esac

echo -e "\033[32m▶ Run environment configuration:\033[0m"
echo "  - Platform: $PLATFORM"
echo "  - Device: $TARGET_ID"
echo "  - Build modes: ${BUILD_MODES[*]}"
echo "  - Debug mode: $DEBUG_MODE"
echo "  - Bundle: $BUNDLE_NAME"
echo "  - Ability: $ABILITY_NAME"
if [ -n "$LOCAL_OHOS_PATH" ]; then
    echo "  - External OHOS path: $LOCAL_OHOS_PATH"
fi
echo "------------------------------------------------------------"

# --- Configuration ---
DEVECO_PATH="${DEVECO_PATH:-/Applications/DevEco-Studio.app}"
MIN_VERSION="6.0.0"

echo "🔍 Checking environment configuration..."

# 1. Check if DevEco exists
if [ ! -d "$DEVECO_PATH" ]; then
    echo "❌ Error: DevEco Studio not found at $DEVECO_PATH."
    exit 1
fi

# 2. Get version (from Info.plist CFBundleShortVersionString)
# Output example: 5.0.3.406
CURRENT_VERSION=$(defaults read "$DEVECO_PATH/Contents/Info.plist" CFBundleShortVersionString)

echo "Current DevEco version: $CURRENT_VERSION"
echo "Minimum required version: $MIN_VERSION"
CUR_MAJOR=$(echo "$CURRENT_VERSION" | cut -d. -f1)
CUR_MINOR=$(echo "$CURRENT_VERSION" | cut -d. -f2)

REQ_MAJOR=$(echo "$MIN_VERSION" | cut -d. -f1)
REQ_MINOR=$(echo "$MIN_VERSION" | cut -d. -f2)

if [ "$CUR_MAJOR" -lt "$REQ_MAJOR" ] 2>/dev/null || \
   { [ "$CUR_MAJOR" -eq "$REQ_MAJOR" ] && [ "$CUR_MINOR" -lt "$REQ_MINOR" ]; }; then
echo "-------------------------------------------------------"
echo -e "${RED}⛔️ Error: DevEco version is too low!${NC}"
echo -e "${RED}Current version: $CURRENT_VERSION${NC}"
echo -e "${RED}Minimum required: $MIN_VERSION+${NC}"
echo -e "${RED}Please upgrade DevEco Studio and run this script again.${NC}"
echo "-------------------------------------------------------"
exit 5
fi

echo "✅ DevEco version meets requirements ($CURRENT_VERSION)"
# ====================== [2. Environment Path and SDK Configuration] ======================
DEVECO_HOME="${DEVECO_HOME:-$DEVECO_PATH/Contents}"
HDC_BIN="$DEVECO_HOME/sdk/default/openharmony/toolchains/hdc"
export DEVECO_SDK_HOME="$DEVECO_HOME/sdk"
export PATH="$DEVECO_SDK_HOME:$DEVECO_HOME/jbr/Contents/Home/bin:$DEVECO_HOME/tools/node/bin:$DEVECO_HOME/tools/ohpm/bin:$DEVECO_HOME/tools/hvigor/bin:$PATH"

if [ "$PLATFORM" = "iosSimulatorArm64" ]; then
    cd "$SCRIPT_DIR"
    echo "Working path: $(pwd)"
    ./gradlew :composeApp:linkDebugFrameworkIosSimulatorArm64
    exit 0
fi

if [ -n "$LOCAL_OHOS_PATH" ]; then
    HARMONY_APP_DIR="$LOCAL_OHOS_PATH"
else
    HARMONY_APP_DIR="$SCRIPT_DIR/harmonyApp"
fi
if [ ! -d "$HARMONY_APP_DIR" ]; then
    echo -e "\033[31mError: harmonyApp directory not found: $HARMONY_APP_DIR\033[0m"
    exit 4
fi

for BUILD_MODE in "${BUILD_MODES[@]}"; do
    echo ""
    echo "============================================================"
    echo " buildMode=$BUILD_MODE "
    echo "============================================================"

    "$HDC_BIN" -t "$TARGET_ID" shell aa force-stop "$BUNDLE_NAME" >/dev/null 2>&1 || true

    # ====================== [3. Gradle Build] ======================
    cd "$SCRIPT_DIR"
    echo "Working path: $(pwd)"
    echo "Building OpenHarmony ($PLATFORM)..."
    if [ "$PLATFORM" = "ohosArm64" ]; then
        if [ "$BUILD_MODE" = "release" ]; then
            if [ -n "$LOCAL_OHOS_PATH" ]; then
                echo "Using external OHOS path: $LOCAL_OHOS_PATH"
                ./gradlew :composeApp:publishReleaseBinariesToHarmonyApp -PharmonyAppPath="$LOCAL_OHOS_PATH"
            else
                ./gradlew :composeApp:publishReleaseBinariesToHarmonyApp
            fi
        else
            if [ -n "$LOCAL_OHOS_PATH" ]; then
                echo "Using external OHOS path: $LOCAL_OHOS_PATH"
                ./gradlew :composeApp:publishDebugBinariesToHarmonyApp -PharmonyAppPath="$LOCAL_OHOS_PATH"
            else
                ./gradlew :composeApp:publishDebugBinariesToHarmonyApp
            fi
        fi
    else
        echo -e "\033[31mError: Unsupported platform '$PLATFORM'\033[0m"
        exit 4
    fi

    HAP_START_TIME=$(date +%s)

    # ====================== [4. HAP Package Build] ======================
    cd "$HARMONY_APP_DIR"
    echo "Switched to harmonyApp directory: $(pwd)"
    echo "Running Hvigor sync and HAP packaging (buildMode=$BUILD_MODE)..."
    ohpm install --all
    node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --sync -p product=default -p buildMode="$BUILD_MODE" --analyze=normal --parallel --incremental --daemon
    if [ "$BUILD_MODE" = "release" ]; then
        node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --mode module -p module=entry -p product=default -p buildMode=release -p requiredDeviceType=phone assembleHap compileNative --analyze=normal --parallel --incremental --daemon
    else
        node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --mode module -p module=entry@default -p product=default -p buildMode=debug -p requiredDeviceType=phone assembleHap --analyze=normal --parallel --incremental --daemon
    fi

    # ====================== [5. Install and Push Debug Components] ======================
    AVAILABLE_TARGETS=$("$HDC_BIN" list targets)
    HAP_DIR="./entry/build/default/outputs/default"
    SIGNED_HAP="entry-default-signed.hap"
    HAP_FILE="$HAP_DIR/$SIGNED_HAP"
    echo "Package path: $HAP_DIR/$SIGNED_HAP"
    if [ ! -f "$HAP_FILE" ]; then
        echo -e "\033[31mError: Signed HAP package not found!\033[0m"
        echo ""
        echo -e "\033[33mExpected path:\033[0m"
        echo "  $HARMONY_APP_DIR/entry/build/default/outputs/default/entry-default-signed.hap"
        echo ""
        exit 6
    fi
    AVAILABLE_TARGETS=$("$HDC_BIN" list targets)
    if ! echo "$AVAILABLE_TARGETS" | grep -q "$TARGET_ID"; then
        echo -e "\033[31mError: Device $TARGET_ID is offline!\033[0m"
        exit 5
    fi

    echo "Pushing debug components and installing HAP..."
    echo "  - Device: $TARGET_ID"
    REMOTE_HAP_DIR="/data/local/tmp/debug_install"
    "$HDC_BIN" -t "$TARGET_ID" shell mkdir -p "$REMOTE_HAP_DIR"
    "$HDC_BIN" -t "$TARGET_ID" file send "$HAP_FILE" "$REMOTE_HAP_DIR"

    INSTALL_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell bm install -p "$REMOTE_HAP_DIR/$SIGNED_HAP" 2>&1)
    sleep 1
    echo "Install status: $INSTALL_OUTPUT"
    if echo "$INSTALL_OUTPUT" | grep -qE "failed"; then
        echo "Install failed detected, uninstalling and reinstalling..."
        "$HDC_BIN" -t "$TARGET_ID" shell bm uninstall -n "$BUNDLE_NAME" >/dev/null 2>&1 || true
        sleep 5
        INSTALL_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell bm install -p "$REMOTE_HAP_DIR/$SIGNED_HAP" 2>&1)
        sleep 5
    fi

    # ====================== [6. App Launch and Debug Mount] ======================
    echo -e "\033[33mLaunching app and starting debug listener...\033[0m"
    "$HDC_BIN" -t "$TARGET_ID" shell rm -rf "$REMOTE_HAP_DIR"
    sleep 1

    echo ""
    echo -e "\033[33m⚠  Important:\033[0m"
    echo -e "  If device screen is locked, please unlock it manually"
    echo ""

    echo "  -> Executing aa start (launch app)..."
    if [ "$DEBUG_MODE" = "debug" ]; then
        echo "  -> Debug mode, starting with -D flag"
        AA_START_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell aa start -a "$ABILITY_NAME" -b "$BUNDLE_NAME" -D 2>&1)
    else
        echo "  -> Attach mode, starting without -D flag"
        AA_START_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell aa start -a "$ABILITY_NAME" -b "$BUNDLE_NAME" 2>&1)
    fi
    END_TIME=$(date +%s)

    AA_START_RESULT=$?
    if echo "$AA_START_OUTPUT" | grep -q "10106102\|screen is locked"; then
        echo -e "\033[31mError: Device screen is locked!\033[0m"
        exit 1
    fi
    if [ $AA_START_RESULT -ne 0 ]; then
        echo -e "\033[33m⚠  App start command returned non-zero exit code, but continuing...\033[0m"
    fi

    "$HDC_BIN" -t "$TARGET_ID" shell mkdir -p /data/local/tmp/debugserver
    "$HDC_BIN" -t "$TARGET_ID" shell rm -f /data/local/tmp/debugserver/lldb-server
    "$HDC_BIN" -t "$TARGET_ID" file send "$DEVECO_HOME/sdk/default/hms/native/lldb/aarch64-linux-ohos/lldb-server" /data/local/tmp/debugserver
    "$HDC_BIN" -t "$TARGET_ID" shell chmod 755 /data/local/tmp/debugserver/lldb-server

    get_pid_func() {
        "$HDC_BIN" -t "$TARGET_ID" shell "pidof $BUNDLE_NAME" 2>/dev/null | tr -d '\r' | tr -d '\n' | awk '{print $1}'
    }

    echo -n "Waiting for app to start"
    MAX_WAIT=20
    COUNT=0
    APP_PID=""
    while [ $COUNT -lt $MAX_WAIT ]; do
        APP_PID=$(get_pid_func)
        if [[ "$APP_PID" =~ ^[0-9]+$ ]]; then
            echo -e "\nApp started (PID: $APP_PID)"
            break
        fi
        echo -n "."
        sleep 1
        let COUNT=COUNT+1
    done

    if [ -z "$APP_PID" ]; then
        echo -e "\n\033[31mFailed: App did not start within expected time!\033[0m"
        exit 1
    fi
    "$HDC_BIN" -t "$TARGET_ID" shell aa attach -b "$BUNDLE_NAME"
    echo "  -> Starting lldb-server and attaching to process (PID: $APP_PID)..."
    "$HDC_BIN" -t "$TARGET_ID" shell aa process -a "$ABILITY_NAME" -b "$BUNDLE_NAME" -D "/data/local/tmp/debugserver/lldb-server platform --listen unix-abstract:///lldb-server/platform.sock"

    echo "------------------------------------------------------------"
    echo -e "\033[32mRound completed (buildMode=$BUILD_MODE)\033[0m"
    echo -e "App info:"
    echo -e "  - Bundle: $BUNDLE_NAME"
    echo -e "  - PID: $APP_PID"
    echo -e "  - Device: $TARGET_ID"
    ELAPSED_TIME=$((HAP_START_TIME - START_TIME))
    MINUTES=$((ELAPSED_TIME / 60))
    SECONDS=$((ELAPSED_TIME % 60))
    echo -e "  - SO build time (from script start): ${MINUTES}m${SECONDS}s (${ELAPSED_TIME}s)"
    ELAPSED_TIME=$((END_TIME - HAP_START_TIME))
    MINUTES=$((ELAPSED_TIME / 60))
    SECONDS=$((ELAPSED_TIME % 60))
    echo -e "  - HAP package and push (this round): ${MINUTES}m${SECONDS}s (${ELAPSED_TIME}s)"
    echo -e "\033[36mNote: You can connect LLDB after each round; last round is the final install on device.\033[0m"
    echo "------------------------------------------------------------"
done

echo -e "\033[32mAll selected build modes finished: ${BUILD_MODES[*]}\033[0m"