#!/data/data/com.termux/files/usr/bin/sh
# zyvo — wrapper that disables Android bionic TBI heap pointer tagging
#
# The real zyvo binary is zyvo.bin; this script LD_PRELOAD's libtagfix.so
# (a constructor that calls mallopt to turn off heap tagging) before exec'ing it.
# Without this, Bun/JSC's NaN-boxing clears the 0xB4 top-byte tag on heap
# pointers, causing bionic to SIGABRT on free(): "Pointer tag ... was truncated".
#
# Permission system: none — everything is allowed by config (beginner CLI
# design, no prompts). The wrapper does not enforce any permissions.
#
# Named sessions: zyvo session <name> — opens <base>/zyvo/<name>/ and
# resumes the previous chat history with --continue. zyvo session = list.
# zyvo menu = interactive menu; zyvo session <number> = resume that one.
#
# Path resolution order (supports both standalone zip and installed package):
#   zip:      wrapper, zyvo.bin, libtagfix.so all live in the same dir
#   installed: bin/zyvo, libexec/opencode/zyvo.bin, lib/libtagfix.so
#   glibc Linux (Ubuntu proot etc.): ~/.local/bin/zyvo, ~/.local/libexec/zyvo/

set -e

dir="$(cd "$(dirname "$0")" && pwd)"
export ANDROID_ROOT="${ANDROID_ROOT:-/system}"
export TERMUX_VERSION="${TERMUX_VERSION:-zyvo-termux}"
export TMPDIR="${ZYVO_TMPDIR:-${HOME:-/data/data/com.termux/files/home}/tmp}"
export TEMP="$TMPDIR"
export TMP="$TMPDIR"
export OPENCODE_DISABLE_TUI_AUDIO="${OPENCODE_DISABLE_TUI_AUDIO:-1}"
mkdir -p "$TMPDIR" 2>/dev/null || true

# ---- zyvo update: reruns the delta installer ----
# (if the core is unchanged it is 0 MB — only the ZYVO layer refreshes)
if [ "${1:-}" = "update" ] || [ "${1:-}" = "upgrade" ]; then
    shift
    echo "zyvo: checking for updates (delta — 0 MB if the core is unchanged)"
    UPDATER_URL="https://raw.githubusercontent.com/zyvo9/zyvo/main/install.sh"
    if curl -fsSL --retry 3 --connect-timeout 15 --max-time 120 -o "$TMPDIR/zyvo-update.sh" "$UPDATER_URL" 2>/dev/null; then
        exec sh "$TMPDIR/zyvo-update.sh" "$@"
    fi
    echo "zyvo: could not fetch the update script — check your internet" >&2
    exit 1
fi

# ---- zyvo uninstall: removes ZYVO cleanly (needs the repo script) ----
if [ "${1:-}" = "uninstall" ]; then
    shift
    UNINSTALLER_URL="https://raw.githubusercontent.com/zyvo9/zyvo/main/scripts/zyvo-uninstall"
    UNINSTALLER=""
    # prefer a local copy (installed layout), else the current repo
    for c in "$dir/../share/zyvo/scripts/zyvo-uninstall" "$dir/zyvo-uninstall" "$TMPDIR/zyvo-uninstall"; do
        if [ -f "$c" ]; then UNINSTALLER="$c"; break; fi
    done
    if [ -z "$UNINSTALLER" ]; then
        if curl -fsSL --retry 2 --connect-timeout 15 --max-time 60 -o "$TMPDIR/zyvo-uninstall" "$UNINSTALLER_URL" 2>/dev/null; then
            UNINSTALLER="$TMPDIR/zyvo-uninstall"
        fi
    fi
    if [ -n "$UNINSTALLER" ]; then
        exec sh "$UNINSTALLER" "$@"
    fi
    echo "zyvo: could not fetch the uninstaller — check your internet" >&2
    exit 1
fi

# ---- zyvo doctor: quick health check + auto-fix ----
if [ "${1:-}" = "doctor" ]; then
    echo "ZYVO doctor — checking..."; echo
    ISSUES=0
    # 1) wrapper
    if [ -f "$dir/zyvo" ] || [ -x "$dir/zyvo" ]; then echo "  ✓ wrapper: $dir/zyvo"
    else echo "  ✗ wrapper missing"; ISSUES=$((ISSUES+1)); fi
    # 2) config dir
    CFG="$HOME/.config/opencode"
    if [ -f "$CFG/opencode.json" ]; then
        # model line (works without python too)
        if grep -q 'deepseek-v4-flash-free' "$CFG/opencode.json" 2>/dev/null; then
            echo "  ✓ model: deepseek-v4-flash-free (default)"
        else
            echo "  ✗ model is NOT deepseek-v4-flash-free — fix with: zyvo update"
            ISSUES=$((ISSUES+1))
        fi
    else
        echo "  ✗ config not found ($CFG) — run: zyvo"
        ISSUES=$((ISSUES+1))
    fi
    # 3) core binary
    CORE=""
    for c in "$dir/../libexec/opencode/opencode.bin" "$HOME/.local/libexec/zyvo/opencode.bin" "${PREFIX:-/data/data/com.termux/files/usr}/libexec/opencode/opencode.bin" "$dir/opencode.bin" "$HOME/.opencode/bin/opencode"; do
        [ -x "$c" ] && { CORE="$c"; break; }
    done
    if [ -n "$CORE" ]; then echo "  ✓ core engine: $CORE"
    else echo "  ✗ core engine missing — run: zyvo"; ISSUES=$((ISSUES+1)); fi
    # 4) version stamp
    STAMP=""
    for s in "$dir/../libexec/opencode/zyvo-core-version" "$HOME/.local/libexec/zyvo/zyvo-core-version" "${PREFIX:-/data/data/com.termux/files/usr}/libexec/opencode/zyvo-core-version"; do
        [ -f "$s" ] && { STAMP="$(cat "$s" 2>/dev/null)"; break; }
    done
    if [ -n "$STAMP" ]; then echo "  ✓ core version: $STAMP"
    else echo "  ✓ core version: (no stamp — will update on next run)"; fi
    # 5) native lib
    NATIVE=""
    for n in "$dir/../lib" "${PREFIX:-/data/data/com.termux/files/usr}/lib" "$HOME/.local/lib/zyvo" "$dir"; do
        [ -f "$n/libtagfix.so" ] && { NATIVE="$n"; break; }
    done
    if [ -n "$NATIVE" ]; then echo "  ✓ native libs: $NATIVE/libtagfix.so"
    else echo "  ⚠ native libs not found (may crash on Android 11+; Linux is fine)"; fi
    # 6) api key in rc
    rc="$HOME/.bashrc"
    if grep -q 'OPENCODE_API_KEY' "$rc" 2>/dev/null || [ -n "$OPENCODE_API_KEY" ]; then
        echo "  ✓ API key configured"
    else
        echo "  ✗ API key not set — add to $rc (or export OPENCODE_API_KEY)"
        ISSUES=$((ISSUES+1))
    fi
    echo
    if [ "$ISSUES" -eq 0 ]; then
        echo "  ✅ All good — ZYVO is ready."
    else
        echo "  ⚠ $ISSUES issue(s) found — fix with: zyvo update  (or rerun: zyvo)"
    fi
    exit 0
fi

# ---- zyvo backup: everything into one .tar.gz ----
if [ "${1:-}" = "backup" ]; then
    shift
    DEST="${1:-$PWD}"
    [ -d "$DEST" ] || { echo "zyvo: no such folder: $DEST" >&2; exit 1; }
    TS="$(date +%Y%m%d-%H%M%S)"
    OUT="$DEST/zyvo-backup-$TS.tar.gz"
    echo "zyvo: backing up config + core + sessions..."
    SRC=""
    [ -d "$HOME/.config/opencode" ] && SRC="$SRC config/opencode"
    [ -f "$HOME/.bashrc" ] && SRC="$SRC bashrc"
    [ -d "$dir/../libexec" ] && SRC="$SRC libexec"
    [ -d "$dir/../lib" ] && SRC="$SRC lib"
    # sessions on shared storage or home
    if [ -d /storage/emulated/0 ]; then SESS="/storage/emulated/0/zyvo"
    elif [ -d /sdcard ]; then SESS="/sdcard/zyvo"
    else SESS="$HOME/zyvo"; fi
    [ -d "$SESS" ] && SRC="$SRC sessions/zyvo"
    if [ -z "$SRC" ]; then
        echo "zyvo: nothing to back up — install first (run: zyvo)" >&2; exit 1
    fi
    # tar with mapping under virtual prefixes
    ( cd "$HOME" && tar -czf "$OUT" \
        --transform "s|^\.config/opencode|configs|" \
        --transform "s|^\.bashrc|shell/rc|" \
        --transform "s|^\.local/libexec/zyvo|core|" \
        --transform "s|^\.local/lib/zyvo|native|" \
        --transform "s|^$SESS|sessions/zyvo|" \
        $SRC 2>/dev/null )
    if [ -f "$OUT" ] && [ -s "$OUT" ]; then
        echo "  ✓ backup: $OUT ($(du -h "$OUT" 2>/dev/null | awk '{print $1}'))"
    else
        echo "  ✗ backup failed" >&2; exit 1
    fi
    exit 0
fi
# Browsers block scripts/fetch/CSS on file:// URLs, so HTML opened directly
# from the file manager often shows a blank page. Serving over http:// fixes it.
if [ "${1:-}" = "preview" ] || [ "${1:-}" = "open" ]; then
    PREVIEW_DIR="${2:-$PWD}"
    [ -d "$PREVIEW_DIR" ] || { echo "zyvo: no such folder: $PREVIEW_DIR" >&2; exit 1; }
    if ! command -v python3 >/dev/null 2>&1; then
        echo "zyvo: python3 is required for the local server — install it (pkg install python)" >&2
        exit 1
    fi
    PORT="${ZYVO_PREVIEW_PORT:-8080}"
    echo "zyvo: serving $PREVIEW_DIR → http://localhost:$PORT"
    echo "      (opens automatically; Ctrl+C stops the server)"
    ( sleep 1.5; command -v termux-open-url >/dev/null 2>&1 \
        && termux-open-url "http://localhost:$PORT/" \
        || command -v xdg-open >/dev/null 2>&1 && xdg-open "http://localhost:$PORT/" ) &
    cd "$PREVIEW_DIR" || exit 1
    exec python3 -m http.server "$PORT" --bind 127.0.0.1
fi

# ---- args: named session (legacy permission flags silently ignored) ----
SESSION_MODE=0
SESSION_NAME=""
while [ "$#" -gt 0 ]; do
    case "$1" in
        --yolo|-y|--safe|--ask) shift; continue;;
        session|sessions|menu)
            SESSION_MODE=1; shift
            [ "$#" -gt 0 ] && { SESSION_NAME="$1"; shift; }
            break;;
        *) break;;
    esac
done

# ---- workspace resolve ----
# The default workspace and named sessions live on top of the shared
# storage base (falling back to home). The storage root holds thousands of
# files (DCIM, WhatsApp, Android/) — working there again makes the phone
# lag and heat up. A fresh dedicated folder = light + fast.
WS_BASE=""
if [ -d /storage/emulated/0 ]; then WS_BASE=/storage/emulated/0
elif [ -d /sdcard ]; then WS_BASE=/sdcard
fi
if [ "$SESSION_MODE" = 1 ]; then
    # Named session = its own folder inside the zyvo/ folder:
    #   /storage/emulated/0/zyvo/<name>/
    SDIR_ROOT="${WS_BASE:-$HOME}/zyvo"
    if [ -z "$SESSION_NAME" ]; then
        # ---- session MENU: box + numbered list + pick ----
        SESS_TMP="$TMPDIR/zyvo-session-list"
        : > "$SESS_TMP" 2>/dev/null || true
        if [ -d "$SDIR_ROOT" ]; then
            for d in "$SDIR_ROOT"/*; do
                [ -d "$d" ] && [ -n "${d##*/}" ] && case "${d##*/}" in
                    .*) ;; *) printf '%s\n' "${d##*/}" >> "$SESS_TMP";;
                esac
            done
        fi
        # newest first
        [ -s "$SESS_TMP" ] && sort -r "$SESS_TMP" -o "$SESS_TMP" 2>/dev/null || true
        echo
        echo "  ┌──────────────────────────────┐"
        echo "  │   ZYVO — SESSIONS            │"
        echo "  │  pick a number to resume     │"
        echo "  │  or type a new session name  │"
        echo "  └──────────────────────────────┘"
        echo
        if [ -s "$SESS_TMP" ]; then
            n=0
            while read -r d; do
                n=$((n+1))
                printf '  [%s]  %s\n' "$n" "$d"
            done < "$SESS_TMP"
        else
            echo "  (no sessions yet — type a name below to create one)"
        fi
        echo
        if [ -t 0 ]; then
            # ---- interactive pick: ↑↓ arrows (or type a number/name) ----
            COUNT="$(wc -l < "$SESS_TMP" 2>/dev/null | tr -d ' ')"
            [ -z "$COUNT" ] && COUNT=0
            SEL=1
            printf '\033[?25l' 2>/dev/null || true   # hide cursor
            while :; do
                # re-render list with highlight
                printf '\033[2A' 2>/dev/null || true
                echo
                if [ "$COUNT" -gt 0 ]; then
                    n=0
                    while read -r d; do
                        n=$((n+1))
                        if [ "$n" -eq "$SEL" ]; then
                            printf '  \033[7m[%s]  %s\033[0m\n' "$n" "$d"
                        else
                            printf '  [%s]  %s\n' "$n" "$d"
                        fi
                    done < "$SESS_TMP"
                else
                    echo "  (no sessions yet — type a name below to create one)"
                fi
                echo
                printf '  \033[90m↑/↓  select   Enter  open   q  quit\033[0m\n'
                printf '  \033[2A\r  → \033[0m' 2>/dev/null || true
                # read one key
                KEY=""
                IFS= read -r -s -n1 KEY || { echo; break; }
                case "$KEY" in
                    $'\x1b') # escape sequence (arrows)
                        IFS= read -r -s -n2 SEQ || true
                        case "$SEQ" in
                            '[A') [ "$SEL" -gt 1 ] && SEL=$((SEL-1));;
                            '[B') [ "$SEL" -lt "$COUNT" ] && SEL=$((SEL+1));;
                        esac
                        ;;
                    '') # Enter
                        if [ "$COUNT" -gt 0 ]; then
                            printf '\033[?25h' 2>/dev/null || true
                            NAME="$(sed -n "${SEL}p" "$SESS_TMP")"
                            exec "$0" session "$NAME"
                        fi
                        ;;
                    q|Q) printf '\033[?25h' 2>/dev/null || true; echo; exit 0;;
                    *[0-9]*) # number → jump
                        case "${KEY}${SEQ:-}" in
                            *[!0-9]*) : ;;
                            *) SEL="${KEY}${SEQ:-}"; [ "$SEL" -gt "$COUNT" ] && SEL="$COUNT";;
                        esac
                        # continue (treat as arrow-selection; Enter opens)
                        ;;
                    *)
                        # a name (letters) → create/join it
                        case "$KEY" in
                            *[!A-Za-z0-9._-]*) : ;;
                            *)
                                printf '\033[?25h' 2>/dev/null || true
                                exec "$0" session "$KEY";;
                        esac
                        ;;
                esac
            done
        else
            echo "Open/new: zyvo session <name>"
            exit 0
        fi
    fi
    case "$SESSION_NAME" in
        ""|"."|".."|*[!A-Za-z0-9._-]*)
            echo "zyvo: session names may only contain a-z 0-9 . _ - (no spaces/symbols)" >&2
            exit 1;;
    esac
    SDIR="$SDIR_ROOT/$SESSION_NAME"
    if mkdir -p "$SDIR" 2>/dev/null && [ -d "$SDIR" ]; then
        cd "$SDIR"
        export OPENCODE_DEFAULT_DIR="$SDIR"
    else
        echo "zyvo: could not create session folder ($SDIR)" >&2
        exit 1
    fi
elif [ "$#" -eq 0 ] && [ "$PWD" = "$HOME" ]; then
    # Default workspace: dedicated folder (not the storage root), only
    # when launching from home without a directory argument.
    if [ -n "$WS_BASE" ]; then
        if mkdir -p "$WS_BASE/zyvo" 2>/dev/null && [ -d "$WS_BASE/zyvo" ]; then
            cd "$WS_BASE/zyvo"
            export OPENCODE_DEFAULT_DIR="$WS_BASE/zyvo"
        else
            cd "$WS_BASE"
            export OPENCODE_DEFAULT_DIR="$WS_BASE"
        fi
    fi
fi

# Set the terminal title so the toolbar shows ZYVO
if ( : >/dev/tty ) 2>/dev/null; then printf '\033]0;ZYVO\007' >/dev/tty 2>/dev/null; fi

# Locate the native libraries we ship alongside the wrapper.
# In the flat layout they sit next to the wrapper; in the Termux package
# layout they are under ../lib; on glibc Linux under ~/.local/lib/zyvo.
NATIVE_LIB_DIR=""
for candidate in \
    "$dir/../lib" \
    "${PREFIX:-/data/data/com.termux/files/usr}/lib" \
    "$HOME/.local/lib/zyvo" \
    "$dir"
do
    if [ -f "$candidate/libtagfix.so" ]; then
        NATIVE_LIB_DIR="$candidate"
        break
    fi
done

if [ -n "$NATIVE_LIB_DIR" ]; then
    export LD_PRELOAD="${NATIVE_LIB_DIR}/libtagfix.so${LD_PRELOAD:+:$LD_PRELOAD}"
    export LD_LIBRARY_PATH="${NATIVE_LIB_DIR}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
    export OPENTUI_LIB_PATH="${NATIVE_LIB_DIR}/libopentui.so"
    if [ -f "${NATIVE_LIB_DIR}/librust_pty_arm64.so" ]; then
        export BUN_PTY_LIB="${NATIVE_LIB_DIR}/librust_pty_arm64.so"
    fi
    export OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER="${OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER:-true}"
    if [ -x "$NATIVE_LIB_DIR/bun" ]; then
        export OPENCODE_BUN_PATH="$NATIVE_LIB_DIR/bun"
    fi
elif [ -n "$PREFIX" ] && [ -d "$PREFIX" ]; then
    # warn only on real Termux — glibc Linux does not need the native lib
    echo "zyvo: warning: native library directory not found, may crash on Android 11+" >&2
fi

# Locate the real binary. Prefer the package layout first so upgrades do not
# accidentally execute a stale flat-layout binary left in $PREFIX/bin.
BIN=""
for candidate in \
    "$dir/../libexec/opencode/opencode.bin" \
    "$HOME/.local/libexec/zyvo/opencode.bin" \
    "${PREFIX:-/data/data/com.termux/files/usr}/libexec/opencode/opencode.bin" \
    "$dir/opencode.bin" \
    "$HOME/.opencode/bin/opencode"
do
    if [ -x "$candidate" ]; then
        BIN="$candidate"
        break
    fi
done
[ -n "$BIN" ] || { echo "zyvo: error: could not find opencode.bin" >&2; exit 127; }

rc=0
if [ "$SESSION_MODE" = 1 ]; then
    "$BIN" --continue "$@" || rc=$?
else
    "$BIN" "$@" || rc=$?
fi
exit $rc
