#!/bin/bash
# PanelX o'rnatuvchisi
#   curl -fsSL https://install.panelx.uz | sudo bash
# Ixtiyoriy: PANELX_NAME=myserver (subdomen nomi), PANELX_PORT=28888
set -euo pipefail

HUB="${PANELX_HUB:-https://panelx.uz}"
DST=/opt/panelx
C='\033[1;36m'; G='\033[1;32m'; Y='\033[1;33m'; R='\033[1;31m'; N='\033[0m'
say()  { printf "${C}==>${N} %s\n" "$*"; }
die()  { printf "${R}Xato:${N} %s\n" "$*" >&2; exit 1; }

[ "$(id -u)" = 0 ] || die "root huquqi kerak: curl -fsSL $HUB/install.sh | sudo bash"
[ -f /etc/os-release ] && . /etc/os-release || die "Noma'lum tizim"
case "${ID:-}" in ubuntu|debian) ;; *) die "Hozircha faqat Ubuntu 20.04+ va Debian 11+ qo'llab-quvvatlanadi";; esac

cat <<'BANNER'

   ██████╗  █████╗ ███╗   ██╗███████╗██╗     ██╗  ██╗
   ██╔══██╗██╔══██╗████╗  ██║██╔════╝██║     ╚██╗██╔╝
   ██████╔╝███████║██╔██╗ ██║█████╗  ██║      ╚███╔╝
   ██╔═══╝ ██╔══██║██║╚██╗██║██╔══╝  ██║      ██╔██╗
   ██║     ██║  ██║██║ ╚████║███████╗███████╗██╔╝ ██╗
   ╚═╝     ╚═╝  ╚═╝╚═╝  ╚═══╝╚══════╝╚══════╝╚═╝  ╚═╝
        Server va hosting boshqaruv paneli

BANNER

export DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=l
say "Tizim paketlari o'rnatilmoqda"
apt-get update -qq
apt-get install -y -qq python3 python3-venv curl openssl ca-certificates tar rsync cron iproute2 >/dev/null

if [ -x /www/server/nginx/sbin/nginx ]; then
  say "aaPanel topildi — PanelX uning yonida ishlaydi"
  NGINX_BIN=/www/server/nginx/sbin/nginx; VHOST_DIR=/www/server/panel/vhost/nginx; WEB_USER=www
  MYSQL_BIN=/www/server/mysql/bin/mysql; MYSQLDUMP_BIN=/www/server/mysql/bin/mysqldump; NGINX_ERR=/www/wwwlogs/nginx_error.log
else
  say "Veb-server (nginx), MariaDB va certbot o'rnatilmoqda"
  apt-get install -y -qq nginx certbot >/dev/null
  command -v mysql >/dev/null || apt-get install -y -qq mariadb-server >/dev/null
  NGINX_BIN=$(command -v nginx); VHOST_DIR=/etc/nginx/conf.d; WEB_USER=www-data
  MYSQL_BIN=$(command -v mysql); MYSQLDUMP_BIN=$(command -v mysqldump); NGINX_ERR=/var/log/nginx/error.log
  if [ -d /run/systemd/system ]; then systemctl enable --now nginx >/dev/null 2>&1 || true; systemctl enable --now mariadb >/dev/null 2>&1 || true
  else (nginx 2>/dev/null || true); (service mariadb start >/dev/null 2>&1 || true); fi
fi
mkdir -p /www/wwwroot/_acme /www/wwwlogs /www/backup/panelx "$DST/data"
chown "$WEB_USER:$WEB_USER" /www/wwwroot/_acme 2>/dev/null || true

say "PanelX yuklab olinmoqda"
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
curl -fsSL "$HUB/release/panelx-latest.tar.gz" -o "$TMP/p.tgz" || die "Reliz yuklab olinmadi ($HUB)"
tar -xzf "$TMP/p.tgz" -C "$TMP"
rsync -a --delete --exclude data --exclude .env --exclude .venv --exclude ssl "$TMP/panelx/" "$DST/"
VERSION=$(cat "$DST/VERSION")
[ -x "$DST/.venv/bin/python" ] || python3 -m venv "$DST/.venv"
"$DST/.venv/bin/pip" install -q --disable-pip-version-check -r "$DST/requirements.txt"

IP=$(curl -fsS4 --max-time 8 https://api.ipify.org 2>/dev/null || hostname -I | awk '{print $1}')
ENVF="$DST/.env"; touch "$ENVF"; chmod 600 "$ENVF"
getenv() { grep -m1 "^$1=" "$ENVF" 2>/dev/null | cut -d= -f2- || true; }
setenv() { if grep -q "^$1=" "$ENVF"; then sed -i "s|^$1=.*|$1=$2|" "$ENVF"; else echo "$1=$2" >> "$ENVF"; fi; }

PORT=$(getenv PORT)
if [ -z "$PORT" ]; then
  PORT=${PANELX_PORT:-}
  while [ -z "$PORT" ] || ss -ltn | grep -q ":$PORT "; do PORT=$(shuf -i 20000-39999 -n1); done
fi
NODE_ID=$(getenv NODE_ID); [ -n "$NODE_ID" ] || NODE_ID=$(openssl rand -hex 16)
NODE_SECRET=$(getenv NODE_SECRET); [ -n "$NODE_SECRET" ] || NODE_SECRET=$(openssl rand -hex 32)
setenv PORT "$PORT"; setenv NODE_ID "$NODE_ID"; setenv NODE_SECRET "$NODE_SECRET"; setenv SERVER_IP "$IP"; setenv HUB "$HUB"
[ -n "$(getenv DIRECT_ACCESS)" ] || setenv DIRECT_ACCESS 1
setenv NGINX_BIN "$NGINX_BIN"; setenv VHOST_DIR "$VHOST_DIR"; setenv WEB_USER "$WEB_USER"
setenv MYSQL_BIN "$MYSQL_BIN"; setenv MYSQLDUMP_BIN "$MYSQLDUMP_BIN"; setenv NGINX_ERR "$NGINX_ERR"
[ -n "$(getenv HUB_IPS)" ] || setenv HUB_IPS "108.181.201.154"

mkdir -p "$DST/ssl"
[ -f "$DST/ssl/cert.pem" ] || openssl req -x509 -nodes -newkey rsa:2048 -days 3650 -subj "/CN=PanelX" \
  -keyout "$DST/ssl/key.pem" -out "$DST/ssl/cert.pem" 2>/dev/null
chmod 600 "$DST/ssl/key.pem"
echo 'map $http_upgrade $connection_upgrade_px { default upgrade; "" close; }' > "$VHOST_DIR/0.panelx_map.conf"
"$NGINX_BIN" -t >/dev/null 2>&1 && "$NGINX_BIN" -s reload 2>/dev/null || true

NEW_USER=""; NEW_PASS=""
HAS_USER=$(cd "$DST/app" && PANELX_DATA=$DST/data PANELX_ENV=$ENVF "$DST/.venv/bin/python" -c "import core;core.init_db()
with core.db() as c: print(c.execute('select count(*) from users').fetchone()[0])")
if [ "$HAS_USER" = "0" ]; then
  NEW_USER=$(python3 -c "import secrets,string;print(secrets.choice(string.ascii_lowercase)+''.join(secrets.choice(string.ascii_lowercase+string.digits) for _ in range(7)))")
  NEW_PASS=$(python3 -c "import secrets,string;print(''.join(secrets.choice(string.ascii_letters+string.digits) for _ in range(16)))")
  (cd "$DST/app" && PANELX_DATA=$DST/data PANELX_ENV=$ENVF "$DST/.venv/bin/python" -c "import core,time,sys
with core.db() as c: c.execute('insert into users(username,pw,created) values(?,?,?)',(sys.argv[1],core.hash_pw(sys.argv[2]),int(time.time())))" "$NEW_USER" "$NEW_PASS")
fi
chown -R root:root "$DST"; chmod 700 "$DST/data"

cat > /usr/local/bin/panelx <<'CLI'
#!/bin/bash
# PanelX boshqaruv buyrug'i
D=/opt/panelx; PY="$D/.venv/bin/python"; export PANELX_DATA=$D/data PANELX_ENV=$D/.env
case "${1:-}" in
  info)    $PY $D/app/cli.py info ;;
  passwd)  $PY $D/app/cli.py passwd ;;
  restart) systemctl restart panelx 2>/dev/null || { pkill -f "uvicorn main:app" ; sleep 1; setsid nohup $D/run.sh >/dev/null 2>&1 < /dev/null & }; echo "qayta ishga tushdi" ;;
  stop)    systemctl stop panelx ;;
  start)   systemctl start panelx ;;
  status)  systemctl status panelx --no-pager | head -5 ;;
  log)     tail -n 100 $D/data/panelx.log ;;
  heartbeat)
    E() { grep -m1 "^$1=" $D/.env | cut -d= -f2-; }
    curl -fsS -m 20 -X POST "$(E HUB)/hub/heartbeat" -H 'Content-Type: application/json' -A PanelX-Node \
      -d "{\"node\":\"$(E NODE_ID)\",\"secret\":\"$(E NODE_SECRET)\",\"port\":$(E PORT)}" ;;
  direct)
    v=$([ "${2:-}" = "on" ] && echo 1 || echo 0); sed -i "s/^DIRECT_ACCESS=.*/DIRECT_ACCESS=$v/" $D/.env; $0 restart
    echo "To'g'ridan kirish: ${2:-off}" ;;
  update)  curl -fsSL "$(grep -m1 ^HUB= $D/.env | cut -d= -f2)/install.sh" | bash ;;
  uninstall)
    read -r -p "PanelX o'chirilsinmi? Saytlar, bazalar va nginx qoladi. (ha/yo'q): " a </dev/tty
    [ "$a" = "ha" ] || exit 0
    systemctl disable --now panelx 2>/dev/null; pkill -f "uvicorn main:app" 2>/dev/null
    rm -rf /etc/systemd/system/panelx.service $D /usr/local/bin/panelx
    (crontab -l 2>/dev/null | grep -v panelx-heartbeat || true) | crontab -
    echo "PanelX o'chirildi." ;;
  *) echo "panelx info | passwd | restart | start | stop | status | log | update | direct on|off | uninstall" ;;
esac
CLI
chmod 755 /usr/local/bin/panelx

cat > "$DST/run.sh" <<RUN
#!/bin/bash
cd $DST/app && PANELX_DATA=$DST/data PANELX_ENV=$ENVF PYTHONUNBUFFERED=1 exec $DST/.venv/bin/uvicorn main:app --host 0.0.0.0 --port $PORT \\
  --ssl-keyfile $DST/ssl/key.pem --ssl-certfile $DST/ssl/cert.pem --no-server-header >> $DST/data/panelx.log 2>&1
RUN
chmod 700 "$DST/run.sh"

start_panel() {
  if [ -d /run/systemd/system ]; then systemctl restart panelx; return; fi
  pkill -f "uvicorn main:app" 2>/dev/null || true
  for i in $(seq 1 20); do ss -ltn | grep -q ":$PORT " || break; sleep 0.5; done
  setsid nohup "$DST/run.sh" >/dev/null 2>&1 < /dev/null &
}

say "Xizmat ishga tushirilmoqda (port $PORT)"
if [ -d /run/systemd/system ]; then
  cat > /etc/systemd/system/panelx.service <<UNIT
[Unit]
Description=PanelX server boshqaruv paneli
After=network.target

[Service]
ExecStart=$DST/run.sh
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
UNIT
  systemctl daemon-reload; systemctl enable -q panelx
fi
start_panel

if command -v ufw >/dev/null && ufw status 2>/dev/null | grep -q "Status: active"; then ufw allow "$PORT/tcp" >/dev/null; fi
for i in $(seq 1 30); do curl -fsSk "https://127.0.0.1:$PORT/api/health" >/dev/null 2>&1 && break; sleep 1; done
curl -fsSk "https://127.0.0.1:$PORT/api/health" >/dev/null || die "Panel ishga tushmadi: tail $DST/data/panelx.log"

say "PanelX tarmog'iga ulanmoqda (subdomen olinmoqda)"
RESP=$(curl -sS --max-time 40 -X POST "$HUB/hub/register" -H 'Content-Type: application/json' -A "PanelX-Installer/$VERSION" \
  -d "{\"node\":\"$NODE_ID\",\"secret\":\"$NODE_SECRET\",\"port\":$PORT,\"name\":\"${PANELX_NAME:-}\",\"version\":\"$VERSION\",\"hostname\":\"$(hostname)\"}" || true)
URL=$(echo "$RESP" | python3 -c 'import json,sys
try: print(json.load(sys.stdin).get("url",""))
except Exception: print("")')
if [ -n "$URL" ]; then
  setenv PANEL_URL "$URL"
  HIPS=$(echo "$RESP" | python3 -c 'import json,sys
print(",".join(json.load(sys.stdin).get("hub_ips",[])))')
  [ -n "$HIPS" ] && setenv HUB_IPS "$HIPS"
  setenv DIRECT_ACCESS 0
  start_panel
  ( crontab -l 2>/dev/null | grep -v 'panelx-heartbeat' || true; echo "*/10 * * * * /usr/local/bin/panelx heartbeat >/dev/null 2>&1 # panelx-heartbeat" ) | crontab -
else
  MSG=$(echo "$RESP" | python3 -c 'import json,sys
try: print(json.load(sys.stdin).get("detail",""))
except Exception: print("")')
  printf "${Y}Subdomen olinmadi:${N} %s\nPanelga to'g'ridan-to'g'ri IP orqali kirishingiz mumkin. Keyinroq: panelx update\n" "${MSG:-hub javob bermadi}"
fi

L="=================================================================="
printf "\n${G}%s${N}\n" "$L"
printf "${G}  PanelX %s muvaffaqiyatli o'rnatildi!${N}\n" "$VERSION"
printf "${G}%s${N}\n" "$L"
[ -n "$URL" ] && printf "  Panel manzili : ${C}%s${N}\n" "$URL"
[ -z "$URL" ] && printf "  To'g'ridan    : https://%s:%s  (o'z-o'zidan imzolangan SSL)\n" "$IP" "$PORT"
if [ -n "$NEW_USER" ]; then
  printf "  Login         : ${Y}%s${N}\n" "$NEW_USER"
  printf "  Parol         : ${Y}%s${N}\n" "$NEW_PASS"
  printf "\n  Login va parolni saqlab qo'ying. Unutsangiz: ${C}panelx passwd${N}\n"
else
  printf "  Login/parol o'zgarmadi. Ko'rish: ${C}panelx info${N} · yangi parol: ${C}panelx passwd${N}\n"
fi
printf "  Port %s tashqi firewall/xavfsizlik guruhida ochiq bo'lishi kerak.\n" "$PORT"
printf "${G}%s${N}\n\n" "$L"
