#!/bin/sh

set -eu

ROOT_DIR=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd)
SCRIPT_UNDER_TEST="$ROOT_DIR/bin/prod/deploy_from_package.sh"

fail() {
    printf 'FAIL: %s\n' "$1" >&2
    exit 1
}

assert_file_exists() {
    file_path="$1"
    [ -e "$file_path" ] || fail "expected file to exist: $file_path"
}

assert_grep() {
    pattern="$1"
    target="$2"
    if ! grep -Eq "$pattern" "$target"; then
        fail "expected pattern [$pattern] in $target"
    fi
}

create_fake_java() {
    fake_java="$1"

    cat > "$fake_java" <<'EOF'
#!/bin/sh
set -eu

port=""
for arg in "$@"; do
    case "$arg" in
        --server.port=*)
            port=${arg#--server.port=}
            ;;
    esac
done

if [ -z "$port" ]; then
    echo "missing port" >&2
    exit 1
fi

while :; do
    sleep 1
done
EOF

    chmod +x "$fake_java"
}

create_release_zip() {
    release_dir="$1"
    release_zip_name="$2"

    mkdir -p "$release_dir/package/deploy" "$release_dir/package/__MACOSX/deploy"
    mkdir -p "$release_dir/package/frontend_payload/dist" "$release_dir/package/frontend_payload/__MACOSX/dist"
    printf 'new-jar\n' > "$release_dir/package/deploy/ruoyi-admin.jar"
    printf 'macos-meta\n' > "$release_dir/package/__MACOSX/deploy/._ruoyi-admin.jar"
    printf '<html>new</html>\n' > "$release_dir/package/frontend_payload/dist/index.html"
    printf 'macos-meta\n' > "$release_dir/package/frontend_payload/__MACOSX/dist/._index.html"
    (
        cd "$release_dir/package/frontend_payload"
        zip -qr "$release_dir/package/dist.zip" dist __MACOSX
    )
    mv "$release_dir/package/dist.zip" "$release_dir/package/deploy/dist.zip"
    (
        cd "$release_dir/package"
        zip -qr "$release_dir/$release_zip_name" deploy __MACOSX
    )
}

find_free_port() {
    python3 - <<'PY'
import socket

sock = socket.socket()
sock.bind(("127.0.0.1", 0))
print(sock.getsockname()[1])
sock.close()
PY
}

prepare_release_dir() {
    release_dir="$1"
    backend_port="$2"

    mkdir -p "$release_dir/backend" "$release_dir/frontend" "$release_dir/fake-java-bin"
    printf 'old-jar\n' > "$release_dir/backend/ruoyi-admin.jar"
    mkdir -p "$release_dir/frontend/dist"
    printf '<html>old</html>\n' > "$release_dir/frontend/dist/index.html"

    create_fake_java "$release_dir/fake-java-bin/java"
    create_release_zip "$release_dir" "deploy.zip"
    cp "$SCRIPT_UNDER_TEST" "$release_dir/deploy_from_package.sh"
    perl -0pi -e "s#JAVA_BIN=\"/home/webapp/env/java/bin/java\"#JAVA_BIN=\"$release_dir/fake-java-bin/java\"#" \
        "$release_dir/deploy_from_package.sh"
    perl -0pi -e "s/BACKEND_PORT=63310/BACKEND_PORT=$backend_port/" \
        "$release_dir/deploy_from_package.sh"
    chmod +x "$release_dir/deploy_from_package.sh"
}

cleanup_release_dir() {
    release_dir="$1"

    if [ -f "$release_dir/backend/backend.pid" ]; then
        backend_pid=$(cat "$release_dir/backend/backend.pid" 2>/dev/null || true)
        if [ -n "${backend_pid:-}" ]; then
            kill "$backend_pid" 2>/dev/null || true
            wait "$backend_pid" 2>/dev/null || true
        fi
    fi

    rm -rf "$release_dir"
}

test_deploy_success() {
    release_dir=$(mktemp -d)
    backend_port=$(find_free_port)
    trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM

    prepare_release_dir "$release_dir" "$backend_port"
    (
        cd "$release_dir"
        ./deploy_from_package.sh
    )

    assert_file_exists "$release_dir/backend/ruoyi-admin.jar"
    assert_file_exists "$release_dir/frontend/dist.zip"
    assert_file_exists "$release_dir/frontend/dist/index.html"
    assert_file_exists "$release_dir/backend/backend.pid"
    assert_file_exists "$release_dir/backend/backend-console.log"
    assert_grep 'new' "$release_dir/frontend/dist/index.html"

    backup_jar_count=$(find "$release_dir/backend" -maxdepth 1 -type f -name 'ruoyi-admin.jar.*.bak' | wc -l | tr -d ' ')
    [ "$backup_jar_count" -eq 1 ] || fail "expected one backup jar, got $backup_jar_count"

    backup_dist_count=$(find "$release_dir/frontend" -maxdepth 1 -type d -name 'dist-*' | wc -l | tr -d ' ')
    [ "$backup_dist_count" -eq 1 ] || fail "expected one backup dist dir, got $backup_dist_count"

    backend_pid=$(cat "$release_dir/backend/backend.pid")
    kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running"

    trap - EXIT INT TERM
    cleanup_release_dir "$release_dir"
}

test_multiple_release_zip_should_fail() {
    release_dir=$(mktemp -d)
    backend_port=$(find_free_port)
    trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM

    prepare_release_dir "$release_dir" "$backend_port"
    cp "$release_dir/deploy.zip" "$release_dir/deploy-copy.zip"

    if (
        cd "$release_dir"
        ./deploy_from_package.sh >/tmp/deploy_from_package_test.stderr 2>&1
    ); then
        fail "expected deploy_from_package.sh to fail when multiple release zips exist"
    fi

    assert_file_exists /tmp/deploy_from_package_test.stderr
    assert_grep '发布 zip 数量不正确' /tmp/deploy_from_package_test.stderr

    rm -f /tmp/deploy_from_package_test.stderr
    trap - EXIT INT TERM
    cleanup_release_dir "$release_dir"
}

test_defunct_process_should_be_ignored() {
    release_dir=$(mktemp -d)
    backend_port=$(find_free_port)
    trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM

    prepare_release_dir "$release_dir" "$backend_port"
    mkdir -p "$release_dir/fake-ps-bin"
    cat > "$release_dir/fake-ps-bin/ps" <<EOF
#!/bin/sh
if [ "\$1" = "-ef" ]; then
    cat <<'PSOUT'
UID   PID  PPID   C STIME   TTY           TIME CMD
root 99999     1   0 00:00   ?        00:00:00 [java] <defunct> -Dloan.pricing.home=$release_dir -jar $release_dir/backend/ruoyi-admin.jar
PSOUT
    exit 0
fi
/bin/ps "\$@"
EOF
    chmod +x "$release_dir/fake-ps-bin/ps"

    (
        cd "$release_dir"
        PATH="$release_dir/fake-ps-bin:/usr/bin:/bin" ./deploy_from_package.sh
    )

    backend_pid=$(cat "$release_dir/backend/backend.pid")
    kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running when defunct process is ignored"

    trap - EXIT INT TERM
    cleanup_release_dir "$release_dir"
}

test_only_current_project_jar_should_match() {
    release_dir=$(mktemp -d)
    backend_port=$(find_free_port)
    trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM

    prepare_release_dir "$release_dir" "$backend_port"
    mkdir -p "$release_dir/fake-ps-bin"
    cat > "$release_dir/fake-ps-bin/ps" <<EOF
#!/bin/sh
if [ "\$1" = "-ef" ]; then
    cat <<'PSOUT'
UID   PID  PPID   C STIME   TTY           TIME CMD
root 88888     1   0 00:00   ?        00:00:00 java -Dloan.pricing.home=$release_dir -jar $release_dir/backend/ruoyi-admin.jar.bak --spring.profiles.active=pro
PSOUT
    exit 0
fi
/bin/ps "\$@"
EOF
    chmod +x "$release_dir/fake-ps-bin/ps"

    (
        cd "$release_dir"
        PATH="$release_dir/fake-ps-bin:/usr/bin:/bin" ./deploy_from_package.sh
    )

    backend_pid=$(cat "$release_dir/backend/backend.pid")
    kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running when non-target jar process is ignored"

    trap - EXIT INT TERM
    cleanup_release_dir "$release_dir"
}

test_should_use_ps_ef_for_process_detection() {
    if rg -n 'pgrep' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
        fail "expected deploy_from_package.sh not to depend on pgrep"
    fi

    if ! rg -n 'ps -ef' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
        fail "expected deploy_from_package.sh to use ps -ef for process detection"
    fi

    if rg -n '\b(ss|lsof|netstat|resolve_frontend_source_dir|is_port_listening)\b' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
        fail "expected deploy_from_package.sh to remove port detection and unzip compatibility helpers"
    fi
}

main() {
    [ -f "$SCRIPT_UNDER_TEST" ] || fail "script under test not found: $SCRIPT_UNDER_TEST"
    test_should_use_ps_ef_for_process_detection
    test_deploy_success
    test_multiple_release_zip_should_fail
    test_defunct_process_should_be_ignored
    test_only_current_project_jar_should_match
    printf 'PASS: deploy_from_package tests\n'
}

main "$@"
