#!/usr/bin/env bash
# ============================================================
# install_frpc.sh - frp 客户端安装脚本（全平台）
#
# 支持: Linux (amd64/arm64) / macOS (amd64/arm64)
#
# 角色:
#   被访问端 (本脚本目标) → 装 frpc，连到 VPS frps
#   主动访问端 (任意设备)  → 只需 SSH 客户端，无需装任何东西
#
# 用法:
#   # 环境变量方式（跳过交互）
#   FRPS_HOST=1.2.3.4 FRPS_PORT=7000 FRPS_TOKEN=xxx bash install_frpc.sh
#
#   # 交互方式（脚本会提示输入缺失的参数）
#   bash install_frpc.sh
#
# 安装后:
#   Linux:  systemctl start|stop|restart|status frpc
#   macOS:  launchctl start|stop com.frpc
# ============================================================

set -euo pipefail

# ============================================================
# ██████  宏定义 / 配置变量（按需修改）
# ██████
# ============================================================

# ---- frps 服务端连接信息（必填！留空则在运行后交互输入）----
FRPS_HOST="${FRPS_HOST:-}"                     # frps 服务器 IP / 域名
FRPS_PORT="${FRPS_PORT:-}"                     # frps 监听端口（默认 7000）
FRPS_TOKEN="${FRPS_TOKEN:-}"                   # 认证令牌（需与 frps 一致）

# ---- frp 版本 & 安装路径 ----
FRP_VERSION="${FRP_VERSION:-}"                 # 留空 = 自动获取最新版；也可手动指定如 "0.61.1"
INSTALL_DIR="/opt/frpc"                        # 安装目录
FRPC_CONF="${INSTALL_DIR}/frpc.toml"           # 配置文件路径
SERVICE_NAME="frpc"                            # 服务名称

# ---- 隧道 / 代理配置（留空则交互询问）----
# 格式: "名称:类型:本地IP:本地端口:远程端口"  多组用换行分隔
# 示例:
#   PRESET_PROXIES="ssh:tcp:127.0.0.1:22:3001
#   web:tcp:127.0.0.1:80:2000"
PRESET_PROXIES="${PRESET_PROXIES:-}"

# ============================================================
# ██████  颜色 & 日志函数
# ██████
# ============================================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'

log_info()  { echo -e "${GREEN}[INFO]${NC}  $*"; }
log_warn()  { echo -e "${YELLOW}[WARN]${NC}  $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
log_step()  { echo -e "\n${CYAN}>>>${NC} ${BOLD}$*${NC}"; }

# ============================================================
# ██████  0. 系统检测
# ██████
# ============================================================
detect_system() {
    case "$(uname -s)" in
        Linux)  OS_TYPE="linux"  ;;
        Darwin) OS_TYPE="darwin" ;;
        *)
            log_error "不支持的系统: $(uname -s)"
            exit 1
            ;;
    esac

    case "$(uname -m)" in
        x86_64)           ARCH="amd64" ;;
        arm64|aarch64)    ARCH="arm64" ;;
        *)
            log_error "不支持的架构: $(uname -m)"
            exit 1
            ;;
    esac
}

# ============================================================
# ██████  辅助函数
# ██████
# ============================================================
get_latest_frp_version() {
    curl -s "https://api.github.com/repos/fatedier/frp/releases/latest" \
        | grep '"tag_name":' \
        | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/' \
        | sed 's/^v//'
}

# ============================================================
# ██████  安装前确认
# ██████
# ============================================================
preflight_confirm() {
    # 先获取版本号（如果未预设）
    if [ -z "$FRP_VERSION" ]; then
        log_info "获取 frp 最新版本号..."
        FRP_VERSION=$(get_latest_frp_version)
        if [ -z "$FRP_VERSION" ] || [ "$FRP_VERSION" = "null" ]; then
            log_error "无法获取最新版本号，请手动设置: export FRP_VERSION=x.x.x"
            exit 1
        fi
    fi

    # 打印安装摘要
    echo ""
    echo -e "${CYAN}╔══════════════════════════════════════════════════╗${NC}"
    echo -e "${CYAN}║${NC}          ${BOLD}frpc 安装 — 安装前确认${NC}                   ${CYAN}║${NC}"
    echo -e "${CYAN}╠══════════════════════════════════════════════════╣${NC}"
    echo -e "${CYAN}║${NC}                                                  ${CYAN}║${NC}"
    echo -e "${CYAN}║${NC}  ${BOLD}目标系统:${NC}   $(uname -s) / $(uname -m) $(printf '%*s' $((38 - ${#OS_TYPE} - ${#ARCH})) '')${CYAN}║${NC}"
    echo -e "${CYAN}║${NC}  ${BOLD}frp 版本:${NC}    v${FRP_VERSION} $(printf '%*s' $((40 - ${#FRP_VERSION})) '')${CYAN}║${NC}"
    echo -e "${CYAN}║${NC}  ${BOLD}安装目录:${NC}    ${INSTALL_DIR} $(printf '%*s' $((38 - ${#INSTALL_DIR})) '')${CYAN}║${NC}"
    echo -e "${CYAN}║${NC}  ${BOLD}配置文件:${NC}    ${FRPC_CONF} $(printf '%*s' $((26 - ${#INSTALL_DIR})) '')${CYAN}║${NC}"
    echo -e "${CYAN}║${NC}                                                  ${CYAN}║${NC}"
    echo -e "${CYAN}║${NC}  ${BOLD}frps 地址:${NC}    ${FRPS_HOST}:${FRPS_PORT} $(printf '%*s' $((32 - ${#FRPS_HOST} - ${#FRPS_PORT})) '')${CYAN}║${NC}"
    echo -e "${CYAN}║${NC}  ${BOLD}认证令牌:${NC}    ${FRPS_TOKEN} $(printf '%*s' $((38 - ${#FRPS_TOKEN})) '')${CYAN}║${NC}"
    echo -e "${CYAN}║${NC}                                                  ${CYAN}║${NC}"

    # 打印预设代理
    if [ -n "$PRESET_PROXIES" ]; then
        echo -e "${CYAN}║${NC}  ${BOLD}预设隧道:${NC}                                      ${CYAN}║${NC}"
        while IFS= read -r line; do
            [ -z "$line" ] && continue
            IFS=':' read -r p_name p_type p_lip p_lport p_rport <<< "$line"
            echo -e "${CYAN}║${NC}    ${p_name} → ${p_type}://${p_lip}:${p_lport} → 远程:${p_rport} $(printf '%*s' $((18 - ${#p_name} - ${#p_type} - ${#p_lip} - ${#p_lport} - ${#p_rport})) '')${CYAN}║${NC}"
        done <<< "$PRESET_PROXIES"
        echo -e "${CYAN}║${NC}                                                  ${CYAN}║${NC}"
    fi

    echo -e "${CYAN}╚══════════════════════════════════════════════════╝${NC}"
    echo ""

    # 用户确认
    read -r -p "确认以上信息无误，继续安装？[Y/n] " confirm
    case "${confirm:-Y}" in
        [Yy]|[Yy][Ee][Ss]) ;;
        *)
            log_warn "用户取消安装"
            exit 0
            ;;
    esac
    echo ""
}

# ============================================================
# ██████  1. 必填参数检查 & 交互补全
# ██████
# ============================================================
check_required_vars() {
    # ---- 首次尝试：从已有配置文件读取 ----
    if [ -f "$FRPC_CONF" ]; then
        log_info "检测到已有配置文件: $FRPC_CONF"
        # 尝试自动提取
        local existing_host existing_port existing_token
        existing_host=$(grep '^serverAddr' "$FRPC_CONF" 2>/dev/null | sed -E 's/.*= *"([^"]+)".*/\1/' || true)
        existing_port=$(grep '^serverPort' "$FRPC_CONF" 2>/dev/null | grep -oE '[0-9]+' || true)
        existing_token=$(grep '^auth.token' "$FRPC_CONF" 2>/dev/null | sed -E 's/.*= *"([^"]+)".*/\1/' || true)

        if [ -n "$existing_host" ] && [ -n "$existing_port" ] && [ -n "$existing_token" ]; then
            log_info "已从现有配置读取: ${existing_host}:${existing_port}"
            [ -z "$FRPS_HOST" ]  && FRPS_HOST="$existing_host"
            [ -z "$FRPS_PORT" ]  && FRPS_PORT="$existing_port"
            [ -z "$FRPS_TOKEN" ] && FRPS_TOKEN="$existing_token"
            return 0
        fi
    fi

    # ---- 检查必填项，缺失则警告并交互输入 ----
    local missing=()

    if [ -z "$FRPS_HOST" ]; then
        missing+=("FRPS_HOST (frps 服务器 IP/域名)")
    fi
    if [ -z "$FRPS_PORT" ]; then
        missing+=("FRPS_PORT (frps 监听端口)")
    fi
    if [ -z "$FRPS_TOKEN" ]; then
        missing+=("FRPS_TOKEN (认证令牌)")
    fi

    if [ ${#missing[@]} -gt 0 ]; then
        echo ""
        echo -e "${YELLOW}╔══════════════════════════════════════════════════╗${NC}"
        echo -e "${YELLOW}║  ⚠  以下必填参数未设置，请补充后继续:           ║${NC}"
        echo -e "${YELLOW}╠══════════════════════════════════════════════════╣${NC}"
        for m in "${missing[@]}"; do
            echo -e "${YELLOW}║     - ${m}$(printf '%*s' $((42 - ${#m})) '')║${NC}"
        done
        echo -e "${YELLOW}╠══════════════════════════════════════════════════╣${NC}"
        echo -e "${YELLOW}║  你可以:                                         ║${NC}"
        echo -e "${YELLOW}║    1. 现在交互输入                               ║${NC}"
        echo -e "${YELLOW}║    2. Ctrl+C 退出，设置环境变量后重新运行:       ║${NC}"
        echo -e "${YELLOW}║       FRPS_HOST=x.x.x.x  FRPS_PORT=7000  \\       ║${NC}"
        echo -e "${YELLOW}║       FRPS_TOKEN=xxx  bash $0                    ║${NC}"
        echo -e "${YELLOW}╚══════════════════════════════════════════════════╝${NC}"
        echo ""
    fi

    # ---- 交互补全 ----
    if [ -z "$FRPS_HOST" ]; then
        read -r -p "请输入 frps 服务器 IP/域名: " FRPS_HOST
        while [ -z "$FRPS_HOST" ]; do
            log_error "FRPS_HOST 不能为空"
            read -r -p "请输入 frps 服务器 IP/域名: " FRPS_HOST
        done
    fi

    if [ -z "$FRPS_PORT" ]; then
        read -r -p "请输入 frps 监听端口 (默认 7000): " FRPS_PORT
        FRPS_PORT="${FRPS_PORT:-7000}"
    fi

    if [ -z "$FRPS_TOKEN" ]; then
        read -r -p "请输入 frps 认证令牌: " FRPS_TOKEN
        while [ -z "$FRPS_TOKEN" ]; do
            log_error "FRPS_TOKEN 不能为空"
            read -r -p "请输入 frps 认证令牌: " FRPS_TOKEN
        done
    fi

    log_info "必填参数检查通过 ✅"
}

# ============================================================
# ██████  2. 下载 frpc
# ██████
# ============================================================
download_frpc() {
    log_step "下载 frpc v${FRP_VERSION}"

    FRP_TAR="frp_${FRP_VERSION}_${OS_TYPE}_${ARCH}.tar.gz"
    FRP_URL="https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/${FRP_TAR}"

    log_info "下载地址: $FRP_URL"
    sudo mkdir -p "$INSTALL_DIR"

    curl -fSL "$FRP_URL" -o "/tmp/${FRP_TAR}"
    tar -xzf "/tmp/${FRP_TAR}" -C /tmp/
    sudo cp "/tmp/frp_${FRP_VERSION}_${OS_TYPE}_${ARCH}/frpc" "$INSTALL_DIR/"
    sudo chmod +x "$INSTALL_DIR/frpc"
    rm -rf "/tmp/${FRP_TAR}" "/tmp/frp_${FRP_VERSION}_${OS_TYPE}_${ARCH}"

    log_info "frpc 已安装到: ${INSTALL_DIR}/frpc"
    log_info "版本信息: $("$INSTALL_DIR/frpc" --version 2>&1 || true)"
}

# ============================================================
# ██████  3. 生成配置文件
# ██████
# ============================================================
generate_config() {
    log_step "生成 frpc 配置"

    PROXY_LINES=""

    if [ -n "$PRESET_PROXIES" ]; then
        # 使用预设代理
        while IFS= read -r line; do
            [ -z "$line" ] && continue
            IFS=':' read -r p_name p_type p_lip p_lport p_rport <<< "$line"
            PROXY_LINES+="# ${p_name}
[[proxies]]
name = \"${p_name}\"
type = \"${p_type}\"
localIP = \"${p_lip}\"
localPort = ${p_lport}
remotePort = ${p_rport}

"
        done <<< "$PRESET_PROXIES"
        log_info "已加载 ${BOLD}$(echo "$PRESET_PROXIES" | grep -c .)${NC} 条预设隧道"
    else
        # 交互式询问
        echo ""
        echo "要暴露本机哪些服务？"
        echo "  1) SSH (端口 22)"
        echo "  2) 自定义端口"
        echo "  3) 跳过，我自己写配置"
        read -r -p "选择 (1/2/3): " svc_choice

        case "${svc_choice:-1}" in
            1)
                read -r -p "远程端口号 (默认 3001): " rport
                rport="${rport:-3001}"
                PROXY_LINES="# SSH 远程访问
[[proxies]]
name = \"ssh\"
type = \"tcp\"
localIP = \"127.0.0.1\"
localPort = 22
remotePort = ${rport}
"
                log_info "SSH 隧道: VPS:${rport} → 本机:22"
                ;;
            2)
                read -r -p "本机服务端口: " lport
                read -r -p "远程端口号: "   rport
                read -r -p "隧道名称: "     pname
                PROXY_LINES="[[proxies]]
name = \"${pname}\"
type = \"tcp\"
localIP = \"127.0.0.1\"
localPort = ${lport}
remotePort = ${rport}
"
                ;;
            3)
                log_info "跳过配置，请手动编辑: $FRPC_CONF"
                ;;
        esac
    fi

    sudo tee "$FRPC_CONF" > /dev/null <<EOF
# ============================================================
# frpc 配置 (TOML 格式, frp >= v0.52.0)
# 文档: https://gofrp.org/docs/
# ============================================================

serverAddr = "${FRPS_HOST}"
serverPort = ${FRPS_PORT}
auth.token = "${FRPS_TOKEN}"

${PROXY_LINES}
EOF

    log_info "配置已写入: $FRPC_CONF"
}

# ============================================================
# ██████  4. 注册系统服务（交互确认）
# ██████
# ============================================================
install_service() {
    log_step "注册系统服务"

    echo ""
    echo -e "是否将 frpc 注册为${BOLD}系统服务${NC}（开机自启、异常自动重启）？"

    if [ "$OS_TYPE" = "linux" ]; then
        echo "  注册后使用: systemctl start|stop|restart|status frpc"
        echo "  配置文件:   /etc/systemd/system/${SERVICE_NAME}.service"
    elif [ "$OS_TYPE" = "darwin" ]; then
        echo "  注册后使用: launchctl start|stop com.frpc"
        echo "  配置文件:   ~/Library/LaunchAgents/com.${SERVICE_NAME}.plist"
    fi

    read -r -p "注册为系统服务？[Y/n] " svc_confirm
    case "${svc_confirm:-Y}" in
        [Yy]|[Yy][Ee][Ss]) ;;
        *)
            log_warn "跳过系统服务注册，你可以稍后手动运行:"
            echo "  ${INSTALL_DIR}/frpc -c ${FRPC_CONF}"
            return 0
            ;;
    esac

    # ---- 实际注册 ----
    if [ "$OS_TYPE" = "linux" ]; then
        _install_systemd
    elif [ "$OS_TYPE" = "darwin" ]; then
        _install_launchd
    fi
}

_install_systemd() {
    local svc_file="/etc/systemd/system/${SERVICE_NAME}.service"

    sudo tee "$svc_file" > /dev/null <<SVC_EOF
[Unit]
Description=frp Client (frpc)
After=network.target network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=${INSTALL_DIR}/frpc -c ${FRPC_CONF}
ExecReload=/bin/kill -HUP \$MAINPID
Restart=on-failure
RestartSec=15s

[Install]
WantedBy=multi-user.target
SVC_EOF

    sudo systemctl daemon-reload
    sudo systemctl enable "$SERVICE_NAME"
    sudo systemctl start "$SERVICE_NAME"

    if systemctl is-active --quiet "$SERVICE_NAME"; then
        log_info "frpc 系统服务已启动 ✅"
    else
        log_error "frpc 启动失败，检查: systemctl status $SERVICE_NAME"
        return 1
    fi

    echo ""
    echo -e "  ${CYAN}管理命令:${NC}"
    echo "    systemctl start   frpc    # 启动"
    echo "    systemctl stop    frpc    # 停止"
    echo "    systemctl restart frpc    # 重启"
    echo "    systemctl status  frpc    # 状态"
    echo "    journalctl -u frpc -f     # 日志"
}

_install_launchd() {
    local plist="$HOME/Library/LaunchAgents/com.${SERVICE_NAME}.plist"

    mkdir -p "$HOME/Library/LaunchAgents"

    cat > "$plist" <<PLIST_EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.${SERVICE_NAME}</string>
    <key>ProgramArguments</key>
    <array>
        <string>${INSTALL_DIR}/frpc</string>
        <string>-c</string>
        <string>${FRPC_CONF}</string>
    </array>
    <key>KeepAlive</key>
    <true/>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardOutPath</key>
    <string>${INSTALL_DIR}/frpc.log</string>
    <key>StandardErrorPath</key>
    <string>${INSTALL_DIR}/frpc_error.log</string>
</dict>
</plist>
PLIST_EOF

    launchctl unload "$plist" 2>/dev/null || true
    launchctl load "$plist"

    log_info "frpc 已启动并设为开机自启 ✅"

    echo ""
    echo -e "  ${CYAN}管理命令:${NC}"
    echo "    launchctl start  com.frpc   # 启动"
    echo "    launchctl stop   com.frpc   # 停止"
    echo "    launchctl unload ~/Library/LaunchAgents/com.frpc.plist  # 卸载"
    echo "    tail -f ${INSTALL_DIR}/frpc.log  # 日志"
}

# ============================================================
# ██████  主流程
# ██████
# ============================================================
main() {
    echo ""
    echo -e "${GREEN}╔══════════════════════════════════════════════════╗${NC}"
    echo -e "${GREEN}║${NC}              ${BOLD}frpc 客户端安装脚本${NC}                    ${GREEN}║${NC}"
    echo -e "${GREEN}╚══════════════════════════════════════════════════╝${NC}"

    detect_system
    check_required_vars
    preflight_confirm
    download_frpc
    generate_config
    install_service

    # ---- 完成 ----
    echo ""
    echo -e "${GREEN}╔══════════════════════════════════════════════════╗${NC}"
    echo -e "${GREEN}║${NC}              ${BOLD}frpc 安装完成 ✅${NC}                        ${GREEN}║${NC}"
    echo -e "${GREEN}╚══════════════════════════════════════════════════╝${NC}"
    echo ""
    echo -e "  ${CYAN}文件位置:${NC}"
    echo "    二进制:  ${INSTALL_DIR}/frpc"
    echo "    配置:    ${FRPC_CONF}"
    echo ""
    echo -e "  ${CYAN}主动访问端 (任意设备, 无需安装):${NC}"
    if grep -q 'remotePort' "$FRPC_CONF" 2>/dev/null; then
        local ssh_port
        ssh_port=$(grep -A5 'name = "ssh"' "$FRPC_CONF" 2>/dev/null | grep 'remotePort' | grep -oE '[0-9]+' || echo "3001")
        echo "    ssh -p ${ssh_port} <本机用户名>@${FRPS_HOST}"
    fi
    echo ""
    echo -e "  ${CYAN}手动运行（未注册服务时）:${NC}"
    echo "    ${INSTALL_DIR}/frpc -c ${FRPC_CONF}"
    echo ""
}

main
