#!/bin/bash
# ============================================================
# Kangle + Easypanel 一键安装
#   架构：Kangle/Easypanel/UI 来自本云端；PHP/MySQL 来自系统官方源
#   支持：Debian 11+ / Ubuntu 20.04+ / CentOS 7
#   用法：bash install.sh [--php=8.2] [--db=mariadb] [--check]
# ============================================================
set -uo pipefail

CLOUD="${CLOUD:-http://kangle.wxin.net}"
PHPV="${PHPV:-}"
DBKIND="${DBKIND:-mariadb}"     # mariadb | mysql
PREFIX=/vhs/kangle
WORK=/root/kangle-install
ADMIN_USER="${ADMIN_USER:-admin}"
MODE=""

for a in "$@"; do
  case "$a" in
    --php=*)  PHPV="${a#*=}" ;;
    --db=*)   DBKIND="${a#*=}" ;;
    --check)  MODE=check ;;
  esac
done

grn(){ printf "\033[32m%s\033[0m\n" "$*"; }
red(){ printf "\033[31m%s\033[0m\n" "$*"; }
ylw(){ printf "\033[33m%s\033[0m\n" "$*"; }
step(){ echo; grn "==== $* ===="; }
die(){ red "$*"; exit 1; }

[ "$(id -u)" = "0" ] || die "需要 root 运行"

# ---------- 0. 系统探测 ----------
. /etc/os-release 2>/dev/null || true
OS_ID="${ID:-unknown}"
OS_VER="${VERSION_ID:-0}"
IS_DEB=$([ -f /etc/debian_version ] && echo 1 || echo 0)

step "0. 环境"
grn "系统: ${PRETTY_NAME:-$OS_ID $OS_VER}  架构: $(uname -m)"
grn "内存: $(free -m | awk '/Mem:/{print $2}')MB  磁盘: $(df -h / | tail -1 | awk '{print $4}') 可用"
[ "$(uname -m)" = "x86_64" ] || die "仅支持 x86_64"

# 默认 PHP 版本（按系统选仓库里最新的稳定版）
if [ -z "$PHPV" ]; then
  case "$OS_ID" in
    debian)  PHPV=8.2 ;;
    ubuntu)  PHPV=$( [ "${OS_VER%%.*}" -ge 24 ] && echo 8.3 || echo 8.1 ) ;;
    centos)  PHPV=82 ;;
    *)       PHPV=8.2 ;;
  esac
fi
grn "PHP 版本: $PHPV   数据库: $DBKIND"

# ---------- 1. 云端可达性 ----------
step "1. 云端包检查"
for f in env/kangle-ent-3.5.21.16-7-x64.tar.gz env/easypanel-2.6.29.tar.gz ui-mine.tar.gz; do
  code=$(curl -s -o /dev/null -m 15 -w '%{http_code}' "$CLOUD/download/$f")
  [ "$code" = "200" ] && grn "$f OK" || die "$f 不可达 (HTTP $code)"
done
[ "$MODE" = "check" ] && { echo; grn "仅检查模式，未做变更"; exit 0; }

# ---------- 2. 依赖与仓库 ----------
step "2. 依赖与软件源"
if [ "$IS_DEB" = "1" ]; then
  export DEBIAN_FRONTEND=noninteractive
  apt-get update -qq || die "apt update 失败"
  apt-get install -y wget curl tar gzip ca-certificates lsb-release apt-transport-https gnupg >/dev/null 2>&1

  # 需要的 PHP 版本不在官方仓库时，加 sury(Debian)/ondrej(Ubuntu) 源
  if ! apt-cache policy "php$PHPV-cgi" 2>/dev/null | grep -q 'Candidate: [0-9]'; then
    ylw "官方仓库没有 php$PHPV，添加第三方 PHP 源"
    apt-get install -y ca-certificates curl gnupg >/dev/null 2>&1
    if [ "$OS_ID" = "debian" ]; then
      curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg
      echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" \
        > /etc/apt/sources.list.d/sury-php.list
    else
      add-apt-repository -y ppa:ondrej/php >/dev/null 2>&1 || {
        apt-get install -y software-properties-common >/dev/null 2>&1
        add-apt-repository -y ppa:ondrej/php >/dev/null 2>&1
      }
    fi
    apt-get update -qq || die "添加 PHP 源后 apt update 失败"
  fi
else
  yum -y install wget curl tar gzip >/dev/null 2>&1
  if ! rpm -q "php${PHPV}-php-cli" >/dev/null 2>&1; then
    ylw "启用 remi 源"
    yum -y install epel-release yum-utils >/dev/null 2>&1
    yum -y install "https://rpms.remirepo.net/enterprise/remi-release-7.rpm" >/dev/null 2>&1
    yum-config-manager --enable "remi-php${PHPV}" >/dev/null 2>&1
  fi
fi
grn "源就绪"

# ---------- 3. 安装 PHP ----------
step "3. 安装 PHP $PHPV"
if [ "$IS_DEB" = "1" ]; then
  PKGS="php$PHPV-cgi php$PHPV-cli php$PHPV-mysql php$PHPV-sqlite3 php$PHPV-mbstring php$PHPV-curl php$PHPV-gd php$PHPV-zip php$PHPV-xml php$PHPV-common"
  apt-get install -y $PKGS >/dev/null 2>&1 || die "PHP 安装失败: $PKGS"
  PHPCGI=$(command -v php-cgi || ls /usr/bin/php-cgi* 2>/dev/null | head -1)
  PHPDIR=/etc/php/$PHPV
  SCANDIR="$PHPDIR/cgi/conf.d"
else
  PKGS="php${PHPV}-php-cli php${PHPV}-php-mysqlnd php${PHPV}-php-pdo php${PHPV}-php-sqlite3 php${PHPV}-php-mbstring php${PHPV}-php-gd php${PHPV}-php-xml php${PHPV}-php-zip"
  yum -y install $PKGS >/dev/null 2>&1 || die "PHP 安装失败: $PKGS"
  PHPCGI="/opt/remi/php${PHPV}/root/usr/bin/php-cgi"
  SCANDIR="/etc/opt/remi/php${PHPV}/php.d"
fi
[ -x "$PHPCGI" ] || die "未找到 php-cgi（预期 $PHPCGI）"
grn "php-cgi: $PHPCGI"
"$PHPCGI" -v | head -1

# ---------- 4. 安装数据库 ----------
step "4. 安装数据库（$DBKIND）"
if [ "$IS_DEB" = "1" ]; then
  if [ "$DBKIND" = "mysql" ]; then
    apt-get install -y mysql-server >/dev/null 2>&1 || die "MySQL 安装失败"
  else
    apt-get install -y mariadb-server >/dev/null 2>&1 || die "MariaDB 安装失败"
  fi
  systemctl enable --now mysql 2>/dev/null || systemctl enable --now mariadb 2>/dev/null
else
  if [ "$DBKIND" = "mysql" ]; then
    yum -y install mysql-server >/dev/null 2>&1 || die "MySQL 安装失败"
    systemctl enable --now mysqld 2>/dev/null
  else
    yum -y install mariadb-server >/dev/null 2>&1 || die "MariaDB 安装失败"
    systemctl enable --now mariadb 2>/dev/null
  fi
fi
sleep 3
MYSQLD=$(command -v mysql || command -v mariadb) || die "未找到 mysql 客户端"
grn "数据库客户端: $MYSQLD"

# ---------- 5. Kangle + 面板 ----------
step "5. 安装 Kangle 与 Easypanel"
mkdir -p "$WORK"; cd "$WORK"
for f in kangle-ent-3.5.21.16-7-x64.tar.gz easypanel-2.6.29.tar.gz; do
  [ -f "$f" ] || curl -sL -o "$f" "$CLOUD/download/env/$f" || die "下载失败 $f"
done
[ -d "$PREFIX" ] && tar czf "/root/kangle_backup_$(date +%s).tar.gz" -C /vhs kangle 2>/dev/null
mkdir -p "$PREFIX"
tar xzf kangle-ent-3.5.21.16-7-x64.tar.gz -C "$PREFIX" --strip-components=1
tar xzf easypanel-2.6.29.tar.gz -C "$PREFIX" --strip-components=1
[ -d "$PREFIX/nodewww/webftp" ] || die "面板解压失败"
chmod 700 "$PREFIX/etc" 2>/dev/null
grn "Kangle + Easypanel 就位"

# ---------- 6. PHP handler（指向系统 php-cgi）----------
step "6. 配置 PHP 处理器"
EXTDIR="$PREFIX/ext/php${PHPV}"
mkdir -p "$EXTDIR"
cat > "$EXTDIR/php-templete.ini" <<'INI'
; 由 install.sh 生成：每站点独立 ini
memory_limit = 256M
max_execution_time = 120
post_max_size = 64M
upload_max_filesize = 64M
date.timezone = Asia/Shanghai
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED
display_errors = Off
log_errors = Off
open_basedir = ${doc_root}:/tmp/
disable_functions = exec,system,passthru,shell_exec,proc_open,popen,pcntl_exec,dl
session.save_path = /tmp
INI

cat > "$PREFIX/ext/php${PHPV}.xml" <<XML
<!--#start 61-->
<config>
<cmd name='php${PHPV}' file='${PHPCGI}' listen='local' lock='0' type='mp' proto='fastcgi'>
<pre_event src_file='%{config_dir}/php-templete.ini' dst_file='/tmp/php-\${name}.ini'/>
<env PHP_FCGI_MAX_REQUESTS='0' PHPRC='/tmp/php-\${name}.ini' PHP_INI_SCAN_DIR='${SCANDIR}'/>
</cmd>
<vhs index='index.php'>
<map file_ext='php' extend='cmd:php${PHPV}' allow_method='*'/>
</vhs>
<vh_templete name='php:php${PHPV}' templete='html' index='index.php'>
<map file_ext='php' extend='cmd:php${PHPV}' allow_method='*'/>
</vh_templete>
</config>
XML
grn "处理器 php${PHPV} → $PHPCGI"

# ---------- 7. 管理凭据（两处必须一致）----------
step "7. 写入管理凭据"
ADMIN_PASS="${ADMIN_PASS:-$(head /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 16)}"
CFG="$PREFIX/etc/config.xml"
if [ -f "$CFG" ]; then
  sed -i "s|<admin user='[^']*' password='[^']*'|<admin user='$ADMIN_USER' password='$ADMIN_PASS'|" "$CFG"
  grep -oE "<admin [^/]*/>" "$CFG" | head -1
fi
cat > "$PREFIX/etc/node.cfg.php" <<PHP
<?php
\$GLOBALS['node_cfg']['localhost']=array('name'=>"localhost",'host'=>"localhost",'port'=>"3311",'user'=>"$ADMIN_USER",'passwd'=>"$ADMIN_PASS",'db_type'=>"mysql",'db_user'=>"easypanel",'db_passwd'=>"$ADMIN_PASS",'win'=>"",'dev'=>"");
PHP
chmod 600 "$PREFIX/etc/node.cfg.php"
grn "凭据已写入（config.xml ⇄ node.cfg.php 一致）"

# ---------- 8. 数据库用户 ----------
step "8. 创建面板数据库用户"
$MYSQLD -uroot -e "CREATE USER IF NOT EXISTS 'easypanel'@'localhost' IDENTIFIED BY '$ADMIN_PASS';" 2>/dev/null
$MYSQLD -uroot -e "GRANT ALL PRIVILEGES ON *.* TO 'easypanel'@'localhost' WITH GRANT OPTION; FLUSH PRIVILEGES;" 2>/dev/null \
  && grn "用户 easypanel 已创建" || ylw "数据库用户创建失败，请检查 root 认证方式"

# ---------- 9. 启动 ----------
step "9. 启动 Kangle"
pkill -f "$PREFIX/bin/kangle" 2>/dev/null; sleep 1
"$PREFIX/bin/kangle" >/dev/null 2>&1
sleep 5
ss -lnt 2>/dev/null | grep -E ':(80|3311|3312) ' | head -3

# ---------- 10. 部署 UI ----------
step "10. 部署面板 UI"
curl -sL -o "$WORK/ui.tgz" "$CLOUD/download/ui-mine.tar.gz" || die "UI 包下载失败"
VH="$PREFIX/nodewww/webftp/vhost"
tar xzf "$WORK/ui.tgz" -C /tmp/
cp -a /tmp/template/. "$VH/view/default/"
for f in /tmp/control/*.ctl.php; do
  [ -f "$f" ] && cp "$f" "$VH/control/" && echo "  控制器: $(basename $f)"
done
grn "UI 已部署"

# ---------- 11. 验收 ----------
step "11. 验收"
LA=$(curl -s -o /dev/null -m 15 -w '%{http_code}' "http://127.0.0.1:3312/admin/?c=session&a=loginForm")
LG=$(curl -s -o /dev/null -m 20 -w '%{http_code}' -c /tmp/.ck -b /tmp/.ck \
      --data "username=$ADMIN_USER&passwd=$ADMIN_PASS" \
      "http://127.0.0.1:3312/admin/index.php?c=session&a=login")
echo "登录页: $LA   登录(POST): $LG  (期望 302)"

echo
if [ "$LG" = "302" ]; then
  grn "================ 安装成功 ================"
else
  ylw "================ 已装完，但登录验证未通过 ================"
  ylw "排查：config.xml 的 <admin> 与 node.cfg.php 是否一致；kangle 3311 是否监听"
fi
cat <<TIP

管理端  http://<IP>:3312/admin/
用户端  http://<IP>:3312/vhost/
账号    $ADMIN_USER
密码    $ADMIN_PASS

组件来源：
  Kangle / Easypanel / UI  ← $CLOUD
  PHP $PHPV ($PHPCGI)
  数据库 $DBKIND（系统官方源）

备份/回滚：
  安装前的 kangle 目录已备份到 /root/kangle_backup_*.tar.gz
TIP
