#!/bin/bash

# Folosește instalarea Go standard dacă există, chiar dacă nu este în PATH.
if [ -x "/usr/local/go/bin/go" ]; then
    export PATH="/usr/local/go/bin:$PATH"
fi

# Încarcă NVM dacă este disponibil
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

# Forțează folosirea versiunii 22
nvm use 22 > /dev/null 2>&1 || echo "⚠️ NVM nu a putut activa Node 22 automatically."

resolve_build_ref() {
    git describe --tags --exact-match 2>/dev/null || git describe --tags --always
}

require_docker_for_darwin_sqlite() {
    if ! command -v docker > /dev/null 2>&1; then
        echo "❌ Docker is required for macOS SQLite cross-builds."
        echo "   Install the Docker CLI in this environment, or use the non-SQLite macOS build option."
        echo "   If you are running inside a code-server container, also mount the host Docker socket."
        exit 1
    fi

    if ! docker info > /dev/null 2>&1; then
        echo "❌ Docker is installed but the daemon is not reachable."
        echo "   Start Docker, or expose the host Docker daemon to this container."
        echo "   For a code-server container, mount /var/run/docker.sock from the host."
        if [ -n "${DOCKER_HOST:-}" ]; then
            echo "   Current DOCKER_HOST: ${DOCKER_HOST}"
        else
            echo "   Current DOCKER_HOST is unset."
        fi
        exit 1
    fi
}

resolve_xgo_image() {
    local xgo_version

    xgo_version="$(awk '$1 == "XGO_VERSION" { print $3; exit }' Makefile 2>/dev/null)"
    if [ -z "$xgo_version" ]; then
        xgo_version="go-1.25.x"
    fi

    printf 'ghcr.io/techknowlogick/xgo:%s' "$xgo_version"
}

resolve_darwin_sqlite_repo_root() {
    local override_path

    override_path="${SMART_BUILD_DARWIN_HOST_REPO_PATH:-}"
    if [ -z "$override_path" ]; then
        pwd -P
        return
    fi

    if [ ! -d "$override_path" ] || [ ! -f "$override_path/go.mod" ]; then
        echo "❌ SMART_BUILD_DARWIN_HOST_REPO_PATH is set, but the path is not usable in this container:"
        echo "   $override_path"
        echo "   Mount the host repository path into the container at the same absolute path, then retry."
        exit 1
    fi

    printf '%s' "$override_path"
}

validate_repo_bind_mount_for_darwin_sqlite() {
    local repo_path="$1"
    local xgo_image

    xgo_image="$(resolve_xgo_image)"

    if ! docker run --rm -v "$repo_path":/probe:ro --entrypoint sh "$xgo_image" -lc 'test -f /probe/go.mod'; then
        echo "❌ Docker can reach the daemon, but the daemon cannot mount this repository path correctly:"
        echo "   $repo_path"
        echo "   The xgo container only sees an empty or different host path, so /source/go.mod is missing there."
        echo "   If smart-build runs inside a code-server container with the host Docker socket,"
        echo "   the repository must be mounted from a host bind path that exists at the same absolute path."
        exit 1
    fi
}

write_sha256_file() {
    local artifact_path="$1"
    local artifact_dir artifact_name

    artifact_dir="$(dirname "$artifact_path")"
    artifact_name="$(basename "$artifact_path")"

    if command -v sha256sum > /dev/null 2>&1; then
        (
            cd "$artifact_dir" || exit 1
            sha256sum "$artifact_name" > "$artifact_name.sha256"
        )
        return
    fi

    if command -v shasum > /dev/null 2>&1; then
        (
            cd "$artifact_dir" || exit 1
            shasum -a 256 "$artifact_name" > "$artifact_name.sha256"
        )
        return
    fi

    echo "❌ Neither sha256sum nor shasum is available for checksum generation."
    exit 1
}

# --- 1. VERIFICARE INTEGRITATE ȘI CURĂȚARE CACHE INIȚIALĂ ---
echo "🔍 Initialization checks..."

if ! command -v go > /dev/null 2>&1; then
    echo "❌ Go nu este disponibil în PATH. Instalează Go 1.26.2 sau adaugă binarul go în PATH."
    exit 1
fi

notify_human_interaction() {
    local bell_oga="/usr/share/sounds/freedesktop/stereo/bell.oga"
    local bell_wav="/usr/share/sounds/alsa/Front_Center.wav"
    local in_vscode_terminal=0
    local notification_sent=0

    if [ "${TERM_PROGRAM:-}" = "vscode" ] || [ -n "${VSCODE_IPC_HOOK_CLI:-}" ] || [ -n "${VSCODE_GIT_IPC_HANDLE:-}" ]; then
        in_vscode_terminal=1
    fi

    if command -v notify-send > /dev/null 2>&1; then
        notify-send "Gitea smart-build" "Human input required in smart-build.sh" > /dev/null 2>&1 && notification_sent=1
    fi

    if command -v canberra-gtk-play > /dev/null 2>&1; then
        canberra-gtk-play -i bell > /dev/null 2>&1 && return
    fi

    if [ -f "$bell_oga" ] && command -v paplay > /dev/null 2>&1; then
        paplay "$bell_oga" > /dev/null 2>&1 && return
    fi

    if [ -f "$bell_wav" ] && command -v aplay > /dev/null 2>&1; then
        aplay -q "$bell_wav" > /dev/null 2>&1 && return
    fi

    if [ -f "$bell_wav" ] && command -v play > /dev/null 2>&1; then
        play -q "$bell_wav" > /dev/null 2>&1 && return
    fi

    if [ -t 1 ]; then
        printf '\a'
    fi

    if [ "$notification_sent" -eq 0 ] && [ "$in_vscode_terminal" -eq 1 ]; then
        printf '\033[1;33m%s\033[0m\n' ">>> Human input required below <<<"
    fi
}

apply_moderate_build_limits() {
    local go_procs="$1"
    local node_memory="$2"

    export GOMAXPROCS="$go_procs"
    export MAKEFLAGS="-j1"

    if [[ "$NODE_OPTIONS" != *"--max-old-space-size="* ]]; then
        export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--max-old-space-size=$node_memory"
    fi
}

echo ""
echo "⚙️ Select Build Load Profile:"
echo "   Normal keeps the default build behavior."
echo "   Moderate limits parallel jobs and keeps CPU/RAM usage lower."
echo "   Low Resource is slower, but safest for weaker machines."
notify_human_interaction
load_options=("Normal" "Moderate (GOMAXPROCS=2, make -j1)" "Low Resource (GOMAXPROCS=1, make -j1)" "Quit")
select opt in "${load_options[@]}"
do
    case $opt in
        "Normal")
            echo "✅ Selected: Normal build profile."
            break
            ;;
        "Moderate (GOMAXPROCS=2, make -j1)")
            apply_moderate_build_limits 2 2048
            echo "✅ Selected: Moderate build profile."
            echo "   GOMAXPROCS=$GOMAXPROCS MAKEFLAGS=\"$MAKEFLAGS\" NODE_OPTIONS=\"$NODE_OPTIONS\""
            break
            ;;
        "Low Resource (GOMAXPROCS=1, make -j1)")
            apply_moderate_build_limits 1 2048
            echo "✅ Selected: Low Resource build profile."
            echo "   GOMAXPROCS=$GOMAXPROCS MAKEFLAGS=\"$MAKEFLAGS\" NODE_OPTIONS=\"$NODE_OPTIONS\""
            break
            ;;
        "Quit")
            exit 0
            ;;
        *) echo "Opțiune invalidă $REPLY";;
    esac
done

# Dacă compilarea anterioară a fost întreruptă, ștergem binarul parțial
if [ -f "gitea" ] || [ -f "gitea.exe" ]; then
    echo "🧹 Garbages found. Cleanning..."
rm -f gitea gitea.exe
fi

# Verificăm dacă node_modules există. Dacă nu, forțăm pnpm install
if [ ! -d "node_modules" ]; then
    echo "⚠️ node_modules missing. Instaling..."
    if ! pnpm install --frozen-lockfile; then
        echo "❌ Fail to install frontend dependencies."
        exit 1
    fi
fi

# --- 2. LOGICĂ FRONTEND (CHECKSUM) ---
CHECKSUM_FILE=".frontend.hash"
CURRENT_HASH=$(find web_src package.json tailwind.config.js -type f -print0 2>/dev/null | xargs -0 sha1sum | sha1sum | awk '{print $1}')

if [ -f "$CHECKSUM_FILE" ] && [ "$CURRENT_HASH" == "$(cat $CHECKSUM_FILE)" ]; then
    echo "✅ Frontend is unchanged."
else
    echo "🚀 Code changes detected. Running frontend build..."
    if ! make frontend; then
        echo "❌ Fail to build frontend assets."
        exit 1
    fi
    echo "$CURRENT_HASH" > "$CHECKSUM_FILE"
fi

# --- 3. MENIU INTERACTIV PENTRU ARHITECTURĂ ---
echo ""
echo "🎯 Select Arch to build:"
notify_human_interaction
arch_options=("linux-amd64" "linux-armv7" "windows-amd64" "macos-amd64" "macos-arm64" "All Arch" "Quit")
select opt in "${arch_options[@]}"
do
    case $opt in
        "linux-amd64")
            TARGETS=("linux/amd64")
            break
            ;;
        "linux-armv7")
            TARGETS=("linux/arm/7")
            break
            ;;
        "windows-amd64")
            TARGETS=("windows/amd64")
            break
            ;;
        "macos-amd64")
            TARGETS=("darwin/amd64")
            break
            ;;
        "macos-arm64")
            TARGETS=("darwin/arm64")
            break
            ;;
        "All Arch")
            TARGETS=("linux/amd64" "linux/arm/7" "windows/amd64" "darwin/amd64" "darwin/arm64")
            break
            ;;
        "Quit")
            exit 0
            ;;
        *) echo "Opțiune invalidă $REPLY";;
    esac
done

echo ""
echo "🏷️ Select Build Tags:"
notify_human_interaction
tag_options=("bindata" "bindata sqlite sqlite_unlock_notify" "Quit")
select opt in "${tag_options[@]}"
do
    case $opt in
        "bindata")
            BUILD_TAGS="bindata"
            break
            ;;
        "bindata sqlite sqlite_unlock_notify")
            BUILD_TAGS="bindata sqlite sqlite_unlock_notify"
            BUILD_VARIANT="sqlite"
            break
            ;;
        "Quit")
            exit 0
            ;;
        *) echo "Opțiune invalidă $REPLY";;
    esac
done

if [ -z "$BUILD_VARIANT" ]; then
    BUILD_VARIANT="default"
fi

BUILD_REF="$(resolve_build_ref)"
BUILD_REF="${BUILD_REF//\//-}"
echo "🏷️ Build tag/reference: $BUILD_REF"

bindata_needs_update() {
    local source_dir="$1"
    local bindata_file="$2"

    if [ ! -f "$bindata_file" ]; then
        return 0
    fi

    find "$source_dir" -type f -newer "$bindata_file" -print -quit 2>/dev/null | grep -q .
}

ensure_bindata_asset() {
    local label="$1"
    local source_dir="$2"
    local go_package="$3"
    local bindata_file="$4"

    if bindata_needs_update "$source_dir" "$bindata_file"; then
        echo "♻️ Regenerating $label bindata..."
        if ! CC= GOOS= GOARCH= CGO_ENABLED=0 go generate -tags bindata "$go_package"; then
            echo "❌ Failed to regenerate $label bindata."
            exit 1
        fi
    else
        echo "✅ $label bindata is up to date."
    fi
}

ensure_bindata_assets() {
    if [[ " $BUILD_TAGS " != *" bindata "* ]]; then
        return
    fi

    echo "🔎 Checking embedded bindata assets..."
    ensure_bindata_asset "templates" "templates" "./modules/templates" "modules/templates/bindata.dat"
    ensure_bindata_asset "options" "options" "./modules/options" "modules/options/bindata.dat"
    ensure_bindata_asset "public" "public" "./modules/public" "modules/public/bindata.dat"
    ensure_bindata_asset "migration schemas" "modules/migration/schemas" "./modules/migration" "modules/migration/bindata.dat"
}

ensure_bindata_assets

build_darwin_sqlite_target() {
    local arch="$1"
    local output="$2"
    local repo_root temp_dist built_file output_abs
    local built_files=()

    require_docker_for_darwin_sqlite
    repo_root="$(resolve_darwin_sqlite_repo_root)"
    validate_repo_bind_mount_for_darwin_sqlite "$repo_root"
    output_abs="$(pwd -P)/$output"

    temp_dist="$repo_root/dist/.smart-build-darwin-${arch}-$$"
    rm -rf "$temp_dist"
    if ! mkdir -p "$temp_dist"; then
        echo "❌ Failed to create a temporary macOS release directory in dist/."
        exit 1
    fi

    echo "📦 Building for darwin/$arch with TAGS=\"$BUILD_TAGS\" via release-darwin..."
    if ! make -C "$repo_root" release-darwin TAGS="$BUILD_TAGS" DARWIN_ARCHS="darwin-10.12/$arch" DIST="$temp_dist"; then
        rm -rf "$temp_dist"
        echo "❌ Fail to build for darwin/$arch with SQLite"
        exit 1
    fi

    mapfile -t built_files < <(find "$temp_dist/binaries" -maxdepth 1 -type f | sort)
    if [ "${#built_files[@]}" -ne 1 ]; then
        rm -rf "$temp_dist"
        echo "❌ Unexpected macOS artifact count for darwin/$arch: ${#built_files[@]}"
        exit 1
    fi
    built_file="${built_files[0]}"

    mv "$built_file" "$output_abs"
    rm -rf "$temp_dist"

    write_sha256_file "$output_abs"
    echo "✅ Created: $output_abs"
    echo "✅ Created: $output_abs.sha256"
}

build_standard_target() {
    local os="$1"
    local arch="$2"
    local arm_ver="$3"
    local output="$4"
    local ext="$5"

    export GOOS=$os
    export GOARCH=$arch
    export GOARM=$arm_ver
    export CGO_ENABLED=0
    if [ "$BUILD_VARIANT" == "sqlite" ]; then
        export CGO_ENABLED=1
    fi

    if make build TAGS="$BUILD_TAGS"; then
        mv "gitea$ext" "$output"
        write_sha256_file "$output"
        echo "✅ Created: $output"
        echo "✅ Created: $output.sha256"
    else
        echo "❌ Fail to build for $os/$arch${arm_ver:+/v$arm_ver}"
        exit 1
    fi
}

# --- 4. COMPILARE ---
mkdir -p dist
for TARGET in "${TARGETS[@]}"; do
    IFS="/" read -r OS ARCH ARM_VER <<< "$TARGET"

    EXT="" && [ "$OS" == "windows" ] && EXT=".exe"
    PLATFORM="$ARCH" && [ ! -z "$ARM_VER" ] && PLATFORM="armv$ARM_VER"
    VARIANT_SUFFIX="" && [ "$BUILD_VARIANT" == "sqlite" ] && VARIANT_SUFFIX="-sqlite"
    OUTPUT="dist/gitea-$BUILD_REF-$OS-$PLATFORM$VARIANT_SUFFIX$EXT"

    if [ "$OS" == "darwin" ] && [ "$BUILD_VARIANT" == "sqlite" ]; then
        build_darwin_sqlite_target "$ARCH" "$OUTPUT"
    else
        echo "📦 Building for $OS/$ARCH ${ARM_VER:+(v$ARM_VER) }with TAGS=\"$BUILD_TAGS\"..."
        build_standard_target "$OS" "$ARCH" "$ARM_VER" "$OUTPUT" "$EXT"
    fi

    unset GOOS GOARCH GOARM CGO_ENABLED
done

echo "✨ Buid finished. Get file(s) from /dist"
go clean -cache # || true
