#!/bin/bash
# ============================================================
# TPanel v1.3.46 一键安装脚本（合并 v1.3.10～v1.3.45 所有修复）
# 官网: https://tpanel.cn
# 作者: Zhang Pu
# 修复: 2026-06-29 - 文件管理-管理员模式增加下载功能（/api/admin/files/download 端点 + 前端按钮）
# 修复: 2026-06-29 - 修复强制刷新后链接点无响应的 bug（Flask send_static_file 默认 12h 缓存，index.html 加 no-cache meta + 后端 _no_cache_html 包装器）
# 修复: 2026-06-29 - 清理 v1.3.34/v1.3.39/v1.3.40 历史备份文件，减少源码包体积
# 修复: 2026-06-28 - v1.3.44 修复：强制刷新后登录态丢失（DOMContentLoaded 加 checkAuth）
# 修复: 2026-06-28 - v1.3.43 新增：一键 SSL 申请 + 数据库密码修改前端联动
# 修复: 2026-06-06 - 仪表盘新增 CPU 核心数 + 型号显示
#                          负载颜色按核心数判断（1 核机器 1.0 算满，N 核机器 N.0 才算满）
# 修复: 2026-06-06 - 安全页"执行安装更新"改用实时进度弹窗（复用软件市场的 SSE 机制）
# 修复: 2026-06-06 - 左侧加"软件"按钮，PHP 多版本 + phpMyAdmin 一键装
#                          装时弹小窗显示 apt install 实时进度（SSE 流）
# 修复: 2026-06-06 - 数据库名变蓝色可点击 → 打开 phpMyAdmin（8443 端口独立）
# 修复: 2026-06-06 - SSL 申请"域名不能为空" bug 修复（if 逻辑反了）
# 修复: 2026-06-06 - 备份加 5 分钟超时 + 错误带 traceback + mysqldump 用 list 参数
# 修复: 2026-06-06 - 修复登录后必须强制刷新才能看到后台的 bug
#                          showLogin() 改用 display 切换两个独立 div，不再 innerHTML 重写 body
# 修复: 2026-06-05 - install.sh 自动安装 MariaDB + 配 sudoers
# 修复: 2026-06-05 - system.py create_mysql_db 改用 sudo + list 参数 + regex 校验（防 SQL 注入）
# 修复: 2026-06-05 - PHP-FPM 改用 TCP 127.0.0.1:9000
# 修复: 2026-06-05 - install.sh 自动安装并启动 PHP-FPM
# 修复: 2026-06-05 - systemd ExecStart 传端口参数
# 修复: 2026-06-05 - 创建 /etc/nginx/tpanel 并授权 tpanel 用户
# 修复: 2026-06-05 - 修复解压步骤漏复制根目录 requirements.txt 等文件
# 修复: 2026-06-05 - 修复 zip 魔数校验永远失败的 bug
# 修复: 2026-06-04 - 修正下载源 URL
# ============================================================set -e

PANEL_VERSION="1.3.48"
PANEL_PORT=8888
GITHUB_REPO="zhang-pu/tpanel"
INSTALL_DIR="/opt/tpanel"
LOG_FILE="/tmp/tpanel_install.log"

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
log()  { echo -e "${GREEN}[$(date +%H:%M:%S)]${NC} $1" | tee -a "$LOG_FILE"; }
warn() { echo -e "${YELLOW}[!]${NC} $1" | tee -a "$LOG_FILE"; }
err()  { echo -e "${RED}[✗]${NC} $1" | tee -a "$LOG_FILE"; }
ok()   { echo -e "${GREEN}[✓]${NC} $1" | tee -a "$LOG_FILE"; }

if [ "$EUID" -ne 0 ]; then
  err "请用 root 用户运行: sudo bash install.sh"; exit 1
fi

# 探测包管理器
if command -v apt-get &>/dev/null; then
  PKG="apt-get"; PKG_UPDATE="apt-get update"; PKG_INSTALL="apt-get install -y"
elif command -v yum &>/dev/null; then
  PKG="yum"; PKG_UPDATE="yum makecache"; PKG_INSTALL="yum install -y"
elif command -v dnf &>/dev/null; then
  PKG="dnf"; PKG_UPDATE="dnf makecache"; PKG_INSTALL="dnf install -y"
else
  err "不支持的发行版（需要 apt / yum / dnf）"; exit 1
fi
log "检测到包管理器: $PKG"

read -p "请输入 TPanel 访问域名（留空用 IP）: " PANEL_DOMAIN
PANEL_DOMAIN=$(echo "$PANEL_DOMAIN" | xargs)

# 1/8 依赖
log "[1/8] 安装系统依赖..."
$PKG_UPDATE >>"$LOG_FILE" 2>&1 || warn "更新源失败，继续..."
# Debian 12+ 添加 Sury PHP 源，支持 PHP 多版本（8.0~8.5）
if [ "$PKG" = "apt-get" ] && [ -f /etc/debian_version ] && grep -q '^12\|bookworm' /etc/debian_version /etc/os-release 2>/dev/null; then
  log "  Debian 12 检测到，添加 Sury PHP 源以支持多版本..."
  $PKG_INSTALL lsb-release apt-transport-https ca-certificates curl gnupg2 >>"$LOG_FILE" 2>&1
  curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg >>"$LOG_FILE" 2>&1
  echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ bookworm main" > /etc/apt/sources.list.d/php.list
  $PKG_UPDATE >>"$LOG_FILE" 2>&1
fi

DEB_PKGS="nginx python3 python3-pip python3-venv sqlite3 certbot python3-certbot-nginx curl wget unzip php8.2-fpm php8.2-cli php8.2-mysql php8.2-curl php8.2-mbstring php8.2-xml php8.2-zip php8.2-gd mariadb-server mariadb-client sudo"
RPM_PKGS="nginx python3 python3-pip sqlite certbot python3-certbot-nginx curl wget unzip php-fpm php-mysqlnd php-curl php-mbstring php-xml php-zip php-gd mariadb-server mariadb sudo"
if [ "$PKG" = "apt-get" ]; then
  $PKG_INSTALL $DEB_PKGS >>"$LOG_FILE" 2>&1 || { err "依赖安装失败，查看 $LOG_FILE"; exit 1; }
else
  $PKG_INSTALL $RPM_PKGS >>"$LOG_FILE" 2>&1 || { err "依赖安装失败，查看 $LOG_FILE"; exit 1; }
fi
# 启动 MariaDB（v1.3.8+）
if [ "$PKG" = "apt-get" ]; then
  systemctl enable mariadb >>"$LOG_FILE" 2>&1 || warn "启用 mariadb 失败，继续..."
  systemctl start mariadb >>"$LOG_FILE" 2>&1 || warn "启动 mariadb 失败，继续..."
else
  systemctl enable mariadb >>"$LOG_FILE" 2>&1 || warn "启用 mariadb 失败，继续..."
  systemctl start mariadb >>"$LOG_FILE" 2>&1 || warn "启动 mariadb 失败，继续..."
fi

# 允许 tpanel 用户免密 sudo 跑 mysql + 系统管理命令（v1.3.46+）
cat > /etc/sudoers.d/tpanel << 'EOF'
Defaults:tpanel !requiretty
tpanel ALL=(ALL) NOPASSWD: /usr/bin/mysql, /usr/sbin/useradd, /usr/sbin/userdel, /usr/sbin/usermod, /usr/bin/chown, /usr/bin/chmod, /usr/sbin/nginx, /usr/bin/systemctl
EOF
chmod 440 /etc/sudoers.d/tpanel
visudo -cf /etc/sudoers.d/tpanel || warn "sudoers 语法校验失败"

# 启动 PHP-FPM（Debian 8.2 / CentOS php-fpm）
if [ "$PKG" = "apt-get" ]; then
  systemctl enable php8.2-fpm >>"$LOG_FILE" 2>&1 || warn "启用 php8.2-fpm 失败，继续..."
  # 改用 TCP 127.0.0.1:9000（避免 unix socket 在某些 systemd 环境失效）
  sed -i 's|^listen = /run/php/php8.2-fpm.sock|listen = 127.0.0.1:9000|' /etc/php/8.2/fpm/pool.d/www.conf 2>/dev/null || warn "修改 PHP-FPM listen 失败"
  systemctl start php8.2-fpm >>"$LOG_FILE" 2>&1 || warn "启动 php8.2-fpm 失败，继续..."
else
  systemctl enable php-fpm >>"$LOG_FILE" 2>&1 || warn "启用 php-fpm 失败，继续..."
  # CentOS/RHEL PHP-FPM 默认就是 TCP 9000，跳过
  systemctl start php-fpm >>"$LOG_FILE" 2>&1 || warn "启动 php-fpm 失败，继续..."
fi
ok "依赖安装完成"

# 2/8 用户和目录
log "[2/8] 创建 TPanel 用户和目录..."
id tpanel &>/dev/null || useradd -r -s /bin/bash -m tpanel
mkdir -p "$INSTALL_DIR"/{backend,frontend,logs,backups,sites,ssl}
# 创建数据目录（v1.3.46+ 修复：config.py 写 .secret_key 需要）
mkdir -p "$INSTALL_DIR/data"

chown -R tpanel:tpanel "$INSTALL_DIR"

# 创建 nginx 配置目录并授权 tpanel 用户（config.py 需要写这里）

chown tpanel:tpanel /etc/nginx/tpanel
chmod 755 /etc/nginx/tpanel

ok "目录就绪: $INSTALL_DIR"

# 3/8 下载源码
log "[3/8] 下载 TPanel v${PANEL_VERSION} 源码..."
TMP_ZIP="/tmp/tpanel-v${PANEL_VERSION}.zip"

# 校验文件是否为合法 zip（看前 4 字节魔数 50 4b 03 04）
is_valid_zip() {
  local file="$1"
  [ -f "$file" ] || return 1
  local magic
  magic=$(od -An -tx1 -N4 "$file" 2>/dev/null | tr -d ' \n')
  [ "$magic" = "504b0304" ]
}

download_from_github() {
  local url="$1"
  log "  尝试下载: $url"
  rm -f "$TMP_ZIP"
  if curl -fsSL --connect-timeout 15 --max-time 300 -o "$TMP_ZIP" "$url" 2>>"$LOG_FILE"; then
    if is_valid_zip "$TMP_ZIP"; then
      return 0
    else
      warn "  下载到的东西不是 zip（可能 404 HTML）"
      return 1
    fi
  else
    warn "  下载失败 (HTTP 错误或网络不通)"
    return 1
  fi
}

# ✅ 修正后的下载源（按优先级，只保留真实存在的）
URLS=(
  # 1. 官网镜像（最快，国内用户友好）
  "https://tpanel.cn/tpanel-v${PANEL_VERSION}-source.zip"
  # 2. GitHub release 当前版本
  "https://github.com/${GITHUB_REPO}/releases/download/v${PANEL_VERSION}/tpanel-v${PANEL_VERSION}-source.zip"
  # 3. latest 通用 - install.sh 路径
  "https://github.com/${GITHUB_REPO}/releases/latest/download/install.sh"
  # 4. 源码 tag zip
  "https://github.com/${GITHUB_REPO}/archive/refs/tags/v${PANEL_VERSION}.zip"
  # 5. main 分支源码 zip
  "https://github.com/${GITHUB_REPO}/archive/refs/heads/main.zip"
)

DOWNLOADED=0
for url in "${URLS[@]}"; do
  if download_from_github "$url"; then
    ok "  源码下载成功 ($(ls -lh $TMP_ZIP | awk '{print $5}'))"
    DOWNLOADED=1
    break
  fi
done

# 本地兜底
if [ $DOWNLOADED -eq 0 ]; then
  for local_zip in /tmp/tpanel.zip /tmp/tpanel_v1.3.zip /tmp/tpanel-v1.3.1.zip /tmp/tpanel-v1.3.1-source.zip; do
    if [ -f "$local_zip" ] && is_valid_zip "$local_zip"; then
      warn "  GitHub 下载失败，使用本地 $local_zip"
      cp "$local_zip" "$TMP_ZIP"
      DOWNLOADED=1
      ok "  使用本地源码"
      break
    fi
  done
fi

if [ $DOWNLOADED -eq 0 ]; then
  err "所有下载源都失败！"
  echo
  echo "  手动下载后放到 /tmp/tpanel.zip 再重跑："
  echo "    wget -O /tmp/tpanel.zip https://tpanel.cn/tpanel-v${PANEL_VERSION}-source.zip"
  echo "    bash install.sh"
  exit 1
fi

# 解压（自适应目录）
log "  解压源码..."
rm -rf "$INSTALL_DIR"/{backend,frontend}
unzip -q -o "$TMP_ZIP" -d /tmp/tpanel_extracted
if [ -d /tmp/tpanel_extracted/tpanel-main ]; then
  EXTRACT_DIR=/tmp/tpanel_extracted/tpanel-main
elif [ -d /tmp/tpanel_extracted/tpanel-${PANEL_VERSION} ]; then
  EXTRACT_DIR=/tmp/tpanel_extracted/tpanel-${PANEL_VERSION}
elif [ -d /tmp/tpanel_extracted/backend ]; then
  EXTRACT_DIR=/tmp/tpanel_extracted
else
  err "  解压目录结构不认识: /tmp/tpanel_extracted/"
  ls -la /tmp/tpanel_extracted/
  exit 1
fi

cp -r "$EXTRACT_DIR"/backend "$INSTALL_DIR/"
cp -r "$EXTRACT_DIR"/frontend "$INSTALL_DIR/"
# 复制根目录的配置文件（如果有）
for f in requirements.txt .gitignore README.md SPEC.md; do
  if [ -f "$EXTRACT_DIR/$f" ]; then
    cp "$EXTRACT_DIR/$f" "$INSTALL_DIR/"
  fi
done
# 创建数据目录（v1.3.46+ 修复：config.py 写 .secret_key 需要）
mkdir -p "$INSTALL_DIR/data"

chown -R tpanel:tpanel "$INSTALL_DIR"
ok "源码部署完成"

# 4/8 venv
log "[4/8] 配置 Python 虚拟环境..."
sudo -u tpanel python3 -m venv "$INSTALL_DIR/venv"
sudo -u tpanel "$INSTALL_DIR/venv/bin/pip" install --upgrade pip >>"$LOG_FILE" 2>&1
sudo -u tpanel "$INSTALL_DIR/venv/bin/pip" install -r "$INSTALL_DIR/requirements.txt" >>"$LOG_FILE" 2>&1 || {
  err "Python 依赖安装失败，查看 $LOG_FILE"; exit 1;
}
ok "Python 环境就绪"

# 5/8 Nginx
log "[5/8] 配置 Nginx..."
cat > /etc/nginx/sites-available/tpanel <<NGINX
server {
    listen 80;
    server_name ${PANEL_DOMAIN:-_};
    client_max_body_size 100M;
    location /static/ { alias ${INSTALL_DIR}/frontend/; }
    location / {
        proxy_pass http://127.0.0.1:${PANEL_PORT};
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }
}
NGINX
ln -sf /etc/nginx/sites-available/tpanel /etc/nginx/sites-enabled/tpanel
rm -f /etc/nginx/sites-enabled/default
nginx -t >>"$LOG_FILE" 2>&1 && systemctl reload nginx
ok "Nginx 配置完成"

# 6/8 systemd
log "[6/8] 注册 systemd 服务..."
cat > /etc/systemd/system/tpanel.service <<SERVICE
[Unit]
Description=TPanel Backend
After=network.target nginx.service
[Service]
Type=simple
User=tpanel
WorkingDirectory=${INSTALL_DIR}
ExecStart=${INSTALL_DIR}/venv/bin/python ${INSTALL_DIR}/backend/main.py ${PANEL_PORT}
Restart=always
RestartSec=5
Environment=TPANEL_PORT=${PANEL_PORT}
Environment=TPANEL_DOMAIN=${PANEL_DOMAIN}
[Install]
WantedBy=multi-user.target
SERVICE
systemctl daemon-reload
systemctl enable tpanel >>"$LOG_FILE" 2>&1
systemctl restart tpanel
sleep 2
if curl -fs http://127.0.0.1:${PANEL_PORT}/api/health >/dev/null 2>&1; then
  ok "TPanel 启动成功"
else
  warn "健康检查失败，查看: journalctl -u tpanel -n 50"
fi

# 7/8 防火墙
log "[7/8] 配置防火墙..."
if command -v ufw &>/dev/null; then
  ufw allow 80/tcp >/dev/null 2>&1 || true
  ufw allow 443/tcp >/dev/null 2>&1 || true
  ok "ufw 规则已添加"
elif command -v firewall-cmd &>/dev/null; then
  firewall-cmd --permanent --add-service=http >/dev/null 2>&1 || true
  firewall-cmd --permanent --add-service=https >/dev/null 2>&1 || true
  firewall-cmd --reload >/dev/null 2>&1 || true
  ok "firewalld 规则已添加"
else
  warn "未检测到防火墙，跳过"
fi

# 8/8 SSL
if [ -n "$PANEL_DOMAIN" ]; then
  log "[8/8] 申请 SSL 证书（${PANEL_DOMAIN}）..."
  if certbot --nginx -d "$PANEL_DOMAIN" --non-interactive --agree-tos -m "admin@${PANEL_DOMAIN}" >>"$LOG_FILE" 2>&1; then
    ok "SSL 证书签发成功"
  else
    warn "SSL 签发失败，稍后手动: certbot --nginx -d ${PANEL_DOMAIN}"
  fi
else
  log "[8/8] 跳过 SSL（无域名）"
fi

ACCESS_URL="http://${PANEL_DOMAIN:-$(curl -s ifconfig.me 2>/dev/null || echo 'YOUR_SERVER_IP')}"
echo
echo "============================================================"
echo -e "${GREEN}  TPanel v${PANEL_VERSION} 安装完成！${NC}"
echo "============================================================"
echo
echo "  访问地址:  ${ACCESS_URL}"
echo "  默认账号:  admin"
echo "  默认密码:  tpanel.cn"
echo
echo -e "${YELLOW}  ⚠️  请登录后立即修改密码！${NC}"
echo
echo -e "${YELLOW}  💡 首次访问请用 Ctrl+Shift+R 硬刷新（跳过浏览器缓存）${NC}"
echo "============================================================"
