#!/bin/bash

set -Eeuo pipefail

# ============================================================
# Rhex Forum 一键安装脚本
# Debian 12
#
# Rhex:
# https://github.com/lovedevpanda/Rhex
#
# 安装：
# Node.js 20
# pnpm 10.33.4
# PostgreSQL 16
# Redis
# Nginx
# PM2
#
# Rhex:
# Web + Worker
# ============================================================

export DEBIAN_FRONTEND=noninteractive

RHEX_VERSION="main"
RHEX_DIR="/opt/rhex"
RHEX_USER="rhex"

RHEX_PORT="3000"

DB_NAME="rhex"
DB_USER="rhex"
DB_PASSWORD="$(openssl rand -hex 24)"

GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
NC='\033[0m'

trap 'echo -e "\n${RED}安装过程中发生错误，行号：$LINENO${NC}"' ERR

echo
echo "============================================================"
echo "              Rhex Forum 一键安装"
echo "============================================================"
echo

# ------------------------------------------------------------
# Root
# ------------------------------------------------------------

if [ "$(id -u)" != "0" ]; then
    echo -e "${RED}请使用 root 用户运行。${NC}"
    exit 1
fi

# ------------------------------------------------------------
# Debian
# ------------------------------------------------------------

if [ ! -f /etc/debian_version ]; then
    echo -e "${RED}此脚本仅支持 Debian。${NC}"
    exit 1
fi

. /etc/os-release

echo -e "${CYAN}系统：${PRETTY_NAME}${NC}"
echo -e "${CYAN}架构：$(dpkg --print-architecture)${NC}"
echo

# ------------------------------------------------------------
# Input
# ------------------------------------------------------------

read -rp "请输入网站域名，例如 forum.example.com： " DOMAIN

if [ -z "$DOMAIN" ]; then
    echo -e "${RED}域名不能为空。${NC}"
    exit 1
fi

read -rp "管理员用户名 [admin]： " ADMIN_USERNAME
ADMIN_USERNAME="${ADMIN_USERNAME:-admin}"

read -rsp "管理员密码 [留空使用随机密码]： " ADMIN_PASSWORD
echo

if [ -z "$ADMIN_PASSWORD" ]; then
    ADMIN_PASSWORD="$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 18)"
fi

read -rp "管理员邮箱 [admin@${DOMAIN}]： " ADMIN_EMAIL
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@${DOMAIN}}"

read -rp "是否自动申请 Let's Encrypt SSL？[Y/n]： " ENABLE_SSL
ENABLE_SSL="${ENABLE_SSL:-Y}"

echo
echo "============================================================"
echo "安装配置"
echo "============================================================"
echo "域名：       $DOMAIN"
echo "管理员：     $ADMIN_USERNAME"
echo "管理员邮箱： $ADMIN_EMAIL"
echo "安装目录：   $RHEX_DIR"
echo "数据库：     $DB_NAME"
echo "数据库用户： $DB_USER"
echo "HTTPS：      $ENABLE_SSL"
echo "============================================================"
echo

read -rp "确认开始安装？[Y/n]： " CONFIRM
CONFIRM="${CONFIRM:-Y}"

if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
    echo "已取消。"
    exit 0
fi

# ------------------------------------------------------------
# Generate secrets
# ------------------------------------------------------------

SESSION_SECRET="$(openssl rand -hex 64)"
CAPTCHA_SECRET_KEY="$(openssl rand -hex 64)"
INTERNAL_REVALIDATION_SECRET="$(openssl rand -hex 64)"

# ------------------------------------------------------------
# System update
# ------------------------------------------------------------

echo
echo -e "${GREEN}[1/11] 更新系统${NC}"

apt-get update

apt-get install -y \
    ca-certificates \
    curl \
    wget \
    git \
    gnupg \
    lsb-release \
    openssl \
    build-essential \
    nginx \
    sudo \
    unzip \
    rsync \
    certbot \
    python3-certbot-nginx

# ------------------------------------------------------------
# Node.js 20
# ------------------------------------------------------------

echo
echo -e "${GREEN}[2/11] 安装 Node.js 20${NC}"

curl -fsSL https://deb.nodesource.com/setup_20.x | bash -

apt-get install -y nodejs

echo
echo "Node:"
node --version

echo "NPM:"
npm --version

NODE_MAJOR="$(node -p 'process.versions.node.split(".")[0]')"

if [ "$NODE_MAJOR" -lt 20 ]; then
    echo -e "${RED}Node.js 版本低于 20，安装失败。${NC}"
    exit 1
fi

# ------------------------------------------------------------
# pnpm
# ------------------------------------------------------------

echo
echo -e "${GREEN}[3/11] 安装 pnpm 10.33.4${NC}"

corepack enable

corepack prepare pnpm@10.33.4 --activate

echo
pnpm --version

# ------------------------------------------------------------
# PostgreSQL 16
# ------------------------------------------------------------

echo
echo -e "${GREEN}[4/11] 安装 PostgreSQL 16${NC}"

if ! command -v psql >/dev/null 2>&1; then

    install -d /usr/share/postgresql-common/pgdg

    curl -fsSL \
        https://www.postgresql.org/media/keys/ACCC4CF8.asc \
        | gpg --dearmor \
        -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.gpg

    echo \
"deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.gpg] http://apt.postgresql.org/pub/repos/apt ${VERSION_CODENAME}-pgdg main" \
        > /etc/apt/sources.list.d/pgdg.list

    apt-get update

    apt-get install -y postgresql-16 postgresql-client-16

else

    echo "PostgreSQL 已安装。"

fi

systemctl enable postgresql
systemctl start postgresql

echo
psql --version

# ------------------------------------------------------------
# Redis
# ------------------------------------------------------------

echo
echo -e "${GREEN}[5/11] 安装 Redis${NC}"

apt-get install -y redis-server

systemctl enable redis-server
systemctl restart redis-server

if ! redis-cli ping | grep -q PONG; then
    echo -e "${RED}Redis 启动失败。${NC}"
    systemctl status redis-server --no-pager
    exit 1
fi

echo "Redis OK"

# ------------------------------------------------------------
# Database
# ------------------------------------------------------------

echo
echo -e "${GREEN}[6/11] 创建 PostgreSQL 数据库${NC}"

sudo -u postgres psql <<EOF

DO \$\$
BEGIN

    IF NOT EXISTS (
        SELECT FROM pg_catalog.pg_roles
        WHERE rolname = '${DB_USER}'
    ) THEN

        CREATE ROLE ${DB_USER}
        LOGIN
        PASSWORD '${DB_PASSWORD}';

    ELSE

        ALTER ROLE ${DB_USER}
        WITH LOGIN
        PASSWORD '${DB_PASSWORD}';

    END IF;

END
\$\$;

SELECT 'CREATE DATABASE ${DB_NAME} OWNER ${DB_USER}'
WHERE NOT EXISTS (
    SELECT FROM pg_database
    WHERE datname = '${DB_NAME}'
)\gexec

ALTER DATABASE ${DB_NAME} OWNER TO ${DB_USER};

EOF

echo "数据库创建完成。"

# ------------------------------------------------------------
# Create Rhex user
# ------------------------------------------------------------

echo
echo -e "${GREEN}[7/11] 创建 Rhex 系统用户${NC}"

if ! id "$RHEX_USER" >/dev/null 2>&1; then

    useradd \
        --system \
        --create-home \
        --home-dir "$RHEX_DIR" \
        --shell /bin/bash \
        "$RHEX_USER"

fi

mkdir -p "$RHEX_DIR"

chown -R "$RHEX_USER:$RHEX_USER" "$RHEX_DIR"

# ------------------------------------------------------------
# Download Rhex
# ------------------------------------------------------------

echo
echo -e "${GREEN}[8/11] 下载 Rhex${NC}"

if [ -d "$RHEX_DIR/.git" ]; then

    echo "检测到已有 Rhex，更新源码。"

    cd "$RHEX_DIR"

    sudo -u "$RHEX_USER" git fetch origin

    sudo -u "$RHEX_USER" git reset --hard origin/main

else

    rm -rf "$RHEX_DIR"

    git clone \
        --depth=1 \
        --branch "$RHEX_VERSION" \
        https://github.com/lovedevpanda/Rhex.git \
        "$RHEX_DIR"

fi

chown -R "$RHEX_USER:$RHEX_USER" "$RHEX_DIR"

cd "$RHEX_DIR"

echo
echo "Rhex commit："
git rev-parse --short HEAD

# ------------------------------------------------------------
# Create .env
# ------------------------------------------------------------

echo
echo -e "${GREEN}[9/11] 创建 Rhex 配置文件${NC}"

DATABASE_URL="postgresql://${DB_USER}:${DB_PASSWORD}@127.0.0.1:5432/${DB_NAME}?schema=public"

cat > "$RHEX_DIR/.env" <<EOF
# ============================================================
# Rhex Production Environment
# ============================================================

NODE_ENV="production"

DATABASE_URL="${DATABASE_URL}"

SESSION_SECRET="${SESSION_SECRET}"

CAPTCHA_SECRET_KEY="${CAPTCHA_SECRET_KEY}"

REDIS_URL="redis://127.0.0.1:6379"

REDIS_KEY_PREFIX="rhex"

REDIS_DB="0"

SITE_URL="https://${DOMAIN}"

APP_URL="https://${DOMAIN}"

NEXT_PUBLIC_SITE_URL="https://${DOMAIN}"

INTERNAL_REVALIDATION_ORIGIN="http://127.0.0.1:${RHEX_PORT}"

INTERNAL_REVALIDATION_SECRET="${INTERNAL_REVALIDATION_SECRET}"

BACKGROUND_JOB_WEB_RUNTIME="worker-only"

BACKGROUND_JOB_CONCURRENCY="10"

BACKGROUND_JOB_MAX_ATTEMPTS="3"

SEED_ADMIN_USERNAME="${ADMIN_USERNAME}"

SEED_ADMIN_PASSWORD="${ADMIN_PASSWORD}"

SEED_ADMIN_EMAIL="${ADMIN_EMAIL}"

SEED_ADMIN_NICKNAME="${ADMIN_USERNAME}"

TZ="Asia/Shanghai"
EOF

chmod 600 "$RHEX_DIR/.env"

chown "$RHEX_USER:$RHEX_USER" "$RHEX_DIR/.env"

# ------------------------------------------------------------
# Install dependencies
# ------------------------------------------------------------

echo
echo -e "${GREEN}[10/11] 安装 Rhex 依赖${NC}"

cd "$RHEX_DIR"

sudo -u "$RHEX_USER" bash <<EOF

set -Eeuo pipefail

cd "$RHEX_DIR"

export HOME="$RHEX_DIR"

export PATH="/usr/local/bin:/usr/bin:/bin:\$HOME/.local/bin:\$HOME/.local/share/pnpm"

corepack enable

corepack prepare pnpm@10.33.4 --activate

echo
echo "pnpm version:"
pnpm --version

echo
echo "开始安装依赖..."

pnpm install --frozen-lockfile

echo
echo "执行 Rhex setup..."

pnpm run setup:prod

echo
echo "开始构建 Rhex..."

pnpm run build

EOF

# ------------------------------------------------------------
# PM2
# ------------------------------------------------------------

echo
echo -e "${GREEN}[11/11] 配置 PM2 / Nginx${NC}"

npm install -g pm2

cat > "$RHEX_DIR/ecosystem.config.cjs" <<EOF
module.exports = {

    apps: [

        {
            name: "rhex-web",

            cwd: "${RHEX_DIR}",

            script: "node_modules/next/dist/bin/next",

            args: "start",

            interpreter: "node",

            env: {
                NODE_ENV: "production",
                PORT: "${RHEX_PORT}",
                HOSTNAME: "127.0.0.1"
            },

            autorestart: true,

            restart_delay: 3000,

            max_memory_restart: "1G",

            time: true
        },

        {
            name: "rhex-worker",

            cwd: "${RHEX_DIR}",

            script: "node_modules/.bin/tsx",

            args: "scripts/worker.ts",

            interpreter: "node",

            env: {
                NODE_ENV: "production",
                NODE_OPTIONS: "--conditions=react-server"
            },

            autorestart: true,

            restart_delay: 5000,

            max_memory_restart: "1G",

            time: true
        }

    ]

}
EOF

chown "$RHEX_USER:$RHEX_USER" "$RHEX_DIR/ecosystem.config.cjs"

# ------------------------------------------------------------
# Nginx
# ------------------------------------------------------------

cat > /etc/nginx/sites-available/rhex.conf <<EOF

server {

    listen 80;

    listen [::]:80;

    server_name ${DOMAIN};

    client_max_body_size 512M;

    proxy_read_timeout 300s;

    proxy_connect_timeout 60s;

    proxy_send_timeout 300s;

    location / {

        proxy_pass http://127.0.0.1:${RHEX_PORT};

        proxy_http_version 1.1;

        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;

        proxy_set_header Upgrade \$http_upgrade;

        proxy_set_header Connection "upgrade";

    }

    location /uploads/ {

        alias ${RHEX_DIR}/uploads/;

        expires 7d;

        add_header Cache-Control "public";

    }

}

EOF

rm -f /etc/nginx/sites-enabled/default

ln -sf \
    /etc/nginx/sites-available/rhex.conf \
    /etc/nginx/sites-enabled/rhex.conf

nginx -t

systemctl enable nginx

systemctl restart nginx

# ------------------------------------------------------------
# Start PM2 as rhex
# ------------------------------------------------------------

echo
echo "启动 Rhex Web + Worker..."

sudo -u "$RHEX_USER" bash <<EOF

set -Eeuo pipefail

export HOME="$RHEX_DIR"

export PATH="/usr/local/bin:/usr/bin:/bin:\$HOME/.local/bin:\$HOME/.local/share/pnpm"

cd "$RHEX_DIR"

pm2 delete rhex-web >/dev/null 2>&1 || true

pm2 delete rhex-worker >/dev/null 2>&1 || true

pm2 start ecosystem.config.cjs

pm2 save

EOF

# ------------------------------------------------------------
# PM2 systemd startup
# ------------------------------------------------------------

echo
echo "配置 PM2 开机启动..."

env PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin \
    pm2 startup systemd \
    -u "$RHEX_USER" \
    --hp "$RHEX_DIR" \
    > /tmp/rhex-pm2-startup.txt 2>&1 || true

STARTUP_COMMAND="$(grep -E '^sudo ' /tmp/rhex-pm2-startup.txt | tail -1 || true)"

if [ -n "$STARTUP_COMMAND" ]; then
    eval "$STARTUP_COMMAND"
fi

sudo -u "$RHEX_USER" pm2 save

# ------------------------------------------------------------
# Wait for Rhex
# ------------------------------------------------------------

echo
echo "等待 Rhex Web 启动..."

sleep 5

if curl -fsS \
    -o /dev/null \
    --max-time 10 \
    "http://127.0.0.1:${RHEX_PORT}"; then

    echo -e "${GREEN}Rhex Web 启动成功。${NC}"

else

    echo -e "${YELLOW}Rhex Web 暂时没有响应。${NC}"
    echo
    echo "PM2 状态："

    sudo -u "$RHEX_USER" pm2 status

    echo
    echo "最近日志："

    sudo -u "$RHEX_USER" pm2 logs rhex-web \
        --lines 50 \
        --nostream || true

fi

# ------------------------------------------------------------
# SSL
# ------------------------------------------------------------

if [[ "$ENABLE_SSL" =~ ^[Yy]$ ]]; then

    echo
    echo "============================================================"
    echo "申请 Let's Encrypt SSL"
    echo "============================================================"

    echo
    echo "请确认域名已经解析到本服务器："
    echo "$DOMAIN"
    echo

    if certbot --nginx \
        -d "$DOMAIN" \
        --non-interactive \
        --agree-tos \
        --register-unsafely-without-email \
        --redirect; then

        echo -e "${GREEN}SSL 安装成功。${NC}"

    else

        echo -e "${YELLOW}SSL 自动申请失败。${NC}"
        echo
        echo "网站仍然可以通过 HTTP 访问："
        echo "http://${DOMAIN}"

    fi

fi

# ------------------------------------------------------------
# Save install information
# ------------------------------------------------------------

cat > /root/rhex-install-info.txt <<EOF
============================================================
Rhex 安装信息
============================================================

网站：
http://${DOMAIN}

HTTPS：
https://${DOMAIN}

Rhex：
${RHEX_DIR}

PostgreSQL：

数据库：
${DB_NAME}

用户名：
${DB_USER}

密码：
${DB_PASSWORD}

管理员：

用户名：
${ADMIN_USERNAME}

密码：
${ADMIN_PASSWORD}

邮箱：
${ADMIN_EMAIL}

Redis：
redis://127.0.0.1:6379

PM2：

Web：
rhex-web

Worker：
rhex-worker

查看状态：

sudo -u ${RHEX_USER} pm2 status

查看 Web：

sudo -u ${RHEX_USER} pm2 logs rhex-web

查看 Worker：

sudo -u ${RHEX_USER} pm2 logs rhex-worker

============================================================
EOF

chmod 600 /root/rhex-install-info.txt

# ------------------------------------------------------------
# Final
# ------------------------------------------------------------

echo
echo
echo "============================================================"
echo -e "${GREEN}                 RHEX 安装完成${NC}"
echo "============================================================"
echo

echo -e "${CYAN}网站：${NC}"
echo "  http://${DOMAIN}"

if [[ "$ENABLE_SSL" =~ ^[Yy]$ ]]; then
    echo "  https://${DOMAIN}"
fi

echo
echo -e "${CYAN}管理员：${NC}"
echo "  用户名：${ADMIN_USERNAME}"
echo "  密码：${ADMIN_PASSWORD}"
echo "  邮箱：${ADMIN_EMAIL}"

echo
echo -e "${CYAN}安装目录：${NC}"
echo "  ${RHEX_DIR}"

echo
echo -e "${CYAN}PM2：${NC}"
echo "  sudo -u ${RHEX_USER} pm2 status"

echo
echo -e "${CYAN}Web 日志：${NC}"
echo "  sudo -u ${RHEX_USER} pm2 logs rhex-web"

echo
echo -e "${CYAN}Worker 日志：${NC}"
echo "  sudo -u ${RHEX_USER} pm2 logs rhex-worker"

echo
echo -e "${CYAN}数据库信息：${NC}"
echo "  数据库：${DB_NAME}"
echo "  用户：${DB_USER}"
echo "  密码：${DB_PASSWORD}"

echo
echo -e "${YELLOW}完整安装信息已保存：${NC}"
echo "  /root/rhex-install-info.txt"

echo
echo "============================================================"
echo