#!/usr/bin/env bash

# ============================================
# 服务器基础环境安装脚本（公共依赖）
# 安装: 系统工具 + Docker + Nginx + Certbot + 防火墙
# 可独立运行，也可被其他部署脚本 source 调用
# ============================================

# 避免重复 source
if [ -n "${_BASE_SETUP_LOADED:-}" ]; then
    return 0 2>/dev/null || true
fi
_BASE_SETUP_LOADED=1

# ===== 终端颜色 =====
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'

log()   { echo -e "${GREEN}[INFO]${NC} $*"; }
warn()  { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
step()  { echo -e "\n${CYAN}========== $* ==========${NC}"; }

# ===== 修复 Windows CRLF 行尾 =====
# 从 Windows scp 上传的文件可能包含 \r，source 时会导致错误
# 用法: fix_crlf file1 [file2 ...]
fix_crlf() {
    for f in "$@"; do
        [ -f "$f" ] && sed -i 's/\r$//' "$f"
    done
}

# ===== 检查 root =====
check_root() {
    if [ "$(id -u)" -ne 0 ]; then
        error "请使用 root 用户运行此脚本: sudo bash $0"
        exit 1
    fi
}

# ===== 检测包管理器 =====
detect_pkg_mgr() {
    if [ -n "${PKG_MGR:-}" ]; then
        return
    fi
    if command -v apt-get &> /dev/null; then
        PKG_MGR="apt"
    elif command -v dnf &> /dev/null; then
        PKG_MGR="dnf"
    elif command -v yum &> /dev/null; then
        PKG_MGR="yum"
    else
        error "不支持的系统，需要 apt/dnf/yum 包管理器"
        exit 1
    fi
}

# ===== 系统初始化 =====
init_system() {
    step "系统初始化"
    detect_pkg_mgr
    log "检测到包管理器: $PKG_MGR"
    log "正在更新系统软件包..."

    case "$PKG_MGR" in
        apt)
            export DEBIAN_FRONTEND=noninteractive
            apt-get update -qq
            apt-get upgrade -y -qq
            apt-get install -y -qq curl wget git gnupg2 ca-certificates \
                lsb-release software-properties-common openssl cron
            ;;
        dnf|yum)
            $PKG_MGR update -y -q
            $PKG_MGR install -y -q curl wget git gnupg2 ca-certificates openssl cronie
            ;;
    esac

    if [ ! -f /etc/timezone ] || [ "$(cat /etc/timezone 2>/dev/null)" != "Asia/Shanghai" ]; then
        timedatectl set-timezone Asia/Shanghai 2>/dev/null || true
        log "时区已设置为 Asia/Shanghai"
    fi

    log "系统初始化完成"
}

# ===== 安装 Docker =====
install_docker() {
    step "安装 Docker"

    if command -v docker &> /dev/null; then
        log "Docker 已安装: $(docker --version)"
    else
        detect_pkg_mgr
        log "正在安装 Docker (使用阿里云镜像)..."

        case "$PKG_MGR" in
            apt)
                curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg \
                    | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
                echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
                    https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" \
                    > /etc/apt/sources.list.d/docker.list
                apt-get update -qq
                apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-compose-plugin
                ;;
            dnf)
                dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
                dnf install -y -q docker-ce docker-ce-cli containerd.io docker-compose-plugin
                ;;
            yum)
                yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
                yum install -y -q docker-ce docker-ce-cli containerd.io docker-compose-plugin
                ;;
        esac
        log "Docker 安装完成: $(docker --version)"
    fi

    systemctl enable --now docker
    log "Docker 服务已启动"

    if ! docker compose version &> /dev/null; then
        error "Docker Compose V2 不可用"
        error "请手动安装: apt install docker-compose-plugin"
        exit 1
    fi
    log "Docker Compose 已就绪: $(docker compose version --short)"
}

# ===== 配置 Docker 镜像加速 =====
configure_docker_mirrors() {
    local mirrors="${DOCKER_REGISTRY_MIRRORS:-}"
    if [ -z "$mirrors" ]; then
        log "未配置 DOCKER_REGISTRY_MIRRORS，跳过镜像加速"
        return
    fi

    mkdir -p /etc/docker

    local json_array
    json_array=$(echo "$mirrors" | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' \
        | grep -v '^$' | awk '{printf "\"%s\",", $0}' | sed 's/,$//')

    local need_restart=0
    if [ -f /etc/docker/daemon.json ]; then
        if ! grep -q "registry-mirrors" /etc/docker/daemon.json; then
            need_restart=1
        fi
    else
        need_restart=1
    fi

    if [ "$need_restart" -eq 1 ]; then
        cat > /etc/docker/daemon.json <<EOF
{
    "registry-mirrors": [${json_array}],
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "10m",
        "max-file": "3"
    }
}
EOF
        log "Docker 镜像加速已配置:"
        echo "$mirrors" | tr ',' '\n' | sed 's/^/  → /'
        systemctl restart docker
        log "Docker 已重启以应用镜像加速"
    else
        log "Docker 镜像加速已存在，跳过"
    fi
}

# ===== 安装 Nginx（官方稳定版仓库）=====
install_nginx() {
    step "安装 Nginx"
    detect_pkg_mgr

    if command -v nginx &> /dev/null; then
        log "Nginx 已安装: $(nginx -v 2>&1)"
    else
        log "正在安装 Nginx（官方 stable 仓库）..."
        case "$PKG_MGR" in
            apt)
                # 添加 Nginx 官方 GPG 密钥
                curl -fsSL https://nginx.org/keys/nginx_signing.key \
                    | gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg
                # 添加官方 stable 仓库
                echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
                    http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \
                    > /etc/apt/sources.list.d/nginx.list
                # 优先使用官方仓库
                printf "Package: *\nPin: origin nginx.org\nPin-Priority: 900\n" \
                    > /etc/apt/preferences.d/99nginx
                apt-get update -qq
                apt-get install -y -qq nginx
                ;;
            dnf)
                cat > /etc/yum.repos.d/nginx.repo <<'REPO'
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
REPO
                dnf install -y -q nginx
                ;;
            yum)
                cat > /etc/yum.repos.d/nginx.repo <<'REPO'
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
REPO
                yum install -y -q nginx
                ;;
        esac
        log "Nginx 安装完成"
    fi

    systemctl enable --now nginx

    mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled /var/www/certbot

    # Nginx 官方包使用 conf.d/ 而非 sites-enabled/，添加 include
    if ! grep -q "sites-enabled" /etc/nginx/nginx.conf; then
        if grep -q "^http {" /etc/nginx/nginx.conf; then
            sed -i '/^http {/a \    include /etc/nginx/sites-enabled/*;' /etc/nginx/nginx.conf
        else
            sed -i '/include.*conf\.d/a \    include /etc/nginx/sites-enabled/*;' /etc/nginx/nginx.conf
        fi
    fi

    log "Nginx 配置就绪"
}

# ===== 安装 Certbot =====
install_certbot() {
    detect_pkg_mgr

    if command -v certbot &> /dev/null; then
        log "Certbot 已安装: $(certbot --version 2>&1)"
        return
    fi

    log "正在安装 Certbot..."
    case "$PKG_MGR" in
        apt) apt-get install -y -qq certbot python3-certbot-nginx ;;
        dnf) dnf install -y -q certbot python3-certbot-nginx ;;
        yum) yum install -y -q certbot python3-certbot-nginx ;;
    esac
    log "Certbot 安装完成"
}

# ===== 配置防火墙（基础端口）=====
setup_firewall_base() {
    step "配置防火墙（基础端口）"

    if command -v ufw &> /dev/null; then
        ufw --force enable 2>/dev/null || true
        ufw allow ssh       comment "SSH"   2>/dev/null || true
        ufw allow 80/tcp    comment "HTTP"  2>/dev/null || true
        ufw allow 443/tcp   comment "HTTPS" 2>/dev/null || true
        ufw reload 2>/dev/null || true
        log "UFW 防火墙规则已添加 (22, 80, 443)"
    elif command -v firewall-cmd &> /dev/null; then
        systemctl enable --now firewalld 2>/dev/null || true
        firewall-cmd --permanent --add-service=ssh   2>/dev/null || true
        firewall-cmd --permanent --add-service=http  2>/dev/null || true
        firewall-cmd --permanent --add-service=https 2>/dev/null || true
        firewall-cmd --reload 2>/dev/null || true
        log "Firewalld 规则已添加 (22, 80, 443)"
    else
        warn "未检测到防火墙工具，请手动开放端口: 22, 80, 443"
    fi
}

# ===== 配置 SSH 公钥认证 =====
# 用法: setup_ssh_key <公钥内容>
# 将公钥写入 ~/.ssh/authorized_keys，自动设置正确权限
setup_ssh_key() {
    local pubkey="$1"

    if [ -z "$pubkey" ]; then
        warn "SSH_PUBLIC_KEY 为空，跳过 SSH 密钥配置"
        return
    fi

    step "配置 SSH 密钥认证"

    mkdir -p /root/.ssh
    chmod 700 /root/.ssh
    touch /root/.ssh/authorized_keys
    chmod 600 /root/.ssh/authorized_keys

    # 幂等：相同公钥不重复写入
    if grep -qF "$pubkey" /root/.ssh/authorized_keys 2>/dev/null; then
        log "SSH 公钥已存在，跳过"
    else
        echo "$pubkey" >> /root/.ssh/authorized_keys
        log "SSH 公钥已添加到 /root/.ssh/authorized_keys"
    fi

    log "SSH 密钥认证配置完成，后续可使用密钥连接，无需输入密码"
}

# ===== 开放额外端口 =====
# 用法: firewall_allow_port <端口> [描述]
firewall_allow_port() {
    local port="$1"
    local comment="${2:-Custom}"

    if command -v ufw &> /dev/null; then
        ufw allow "$port"/tcp comment "$comment" 2>/dev/null || true
        ufw reload 2>/dev/null || true
    elif command -v firewall-cmd &> /dev/null; then
        firewall-cmd --permanent --add-port="$port"/tcp 2>/dev/null || true
        firewall-cmd --reload 2>/dev/null || true
    fi
    log "已开放端口: $port ($comment)"
}

# ===== 申请 SSL 证书 =====
# 用法: setup_ssl_cert <域名> <邮箱> [站点名称]
setup_ssl_cert() {
    local domain="$1"
    local email="$2"
    local site_name="${3:-$domain}"

    step "配置 SSL 证书: ${domain}"

    install_certbot

    # 部署临时 Nginx 配置（仅 HTTP，用于 ACME 验证）
    cat > "/etc/nginx/sites-available/${site_name}" <<NGINX_TEMP
server {
    listen 80;
    listen [::]:80;
    server_name ${domain};

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 200 'Service is being configured...';
        add_header Content-Type text/plain;
    }
}
NGINX_TEMP

    ln -sf "/etc/nginx/sites-available/${site_name}" "/etc/nginx/sites-enabled/${site_name}"
    # 移除默认站点避免冲突（Ubuntu 包和官方包路径不同）
    rm -f /etc/nginx/sites-enabled/default
    rm -f /etc/nginx/conf.d/default.conf
    nginx -t && systemctl reload nginx

    # 申请证书
    if [ ! -d "/etc/letsencrypt/live/${domain}" ]; then
        log "正在申请 SSL 证书: ${domain} ..."
        if ! certbot certonly --webroot \
            -w /var/www/certbot \
            -d "${domain}" \
            --email "${email}" \
            --agree-tos \
            --non-interactive \
            --no-eff-email; then
            error "SSL 证书申请失败！"
            error "请确认："
            error "  1. 域名 ${domain} 已解析到本服务器 IP"
            error "  2. 服务器 80 端口可从外网访问"
            exit 1
        fi
        log "SSL 证书申请成功"
    else
        log "SSL 证书已存在，跳过申请"
    fi

    # 配置自动续期
    if ! crontab -l 2>/dev/null | grep -q "certbot renew"; then
        (crontab -l 2>/dev/null; echo "0 3 * * * certbot renew --quiet --post-hook 'systemctl reload nginx'") | crontab -
        log "已配置 SSL 证书自动续期 (每天 03:00 检查)"
    fi
}

# ===== 部署 Nginx 配置 =====
# 用法: deploy_nginx_conf <模板路径> <域名> <站点名称>
# 模板中使用 __DOMAIN__ 作为域名占位符
deploy_nginx_conf() {
    local template="$1"
    local domain="$2"
    local site_name="$3"

    if [ ! -f "$template" ]; then
        error "Nginx 配置模板不存在: $template"
        exit 1
    fi

    cp "$template" "/etc/nginx/sites-available/${site_name}"
    sed -i "s/__DOMAIN__/${domain}/g" "/etc/nginx/sites-available/${site_name}"

    ln -sf "/etc/nginx/sites-available/${site_name}" "/etc/nginx/sites-enabled/${site_name}"

    nginx -t
    systemctl reload nginx
    log "Nginx 反向代理配置已部署: ${site_name} → ${domain}"
}

# ===== 加载 base .env =====
load_base_env() {
    local base_dir="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
    if [ -f "$base_dir/.env" ]; then
        fix_crlf "$base_dir/.env"
        set -a
        source "$base_dir/.env"
        set +a
    fi
}

# =============================================================
#  独立运行模式：直接安装全部基础环境
# =============================================================
_base_main() {
    echo -e "${CYAN}"
    echo "  ____"
    echo " | __ )  __ _ ___  ___"
    echo " |  _ \\ / _\` / __|/ _ \\"
    echo " | |_) | (_| \\__ \\  __/"
    echo " |____/ \\__,_|___/\\___|  Server Base Setup"
    echo -e "${NC}"
    echo ""

    check_root

    local base_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

    # 加载 .env
    if [ -f "$base_dir/.env" ]; then
        set -a; source "$base_dir/.env"; set +a
    elif [ -f "$base_dir/.env.example" ]; then
        cp "$base_dir/.env.example" "$base_dir/.env"
        set -a; source "$base_dir/.env"; set +a
        log "已从 .env.example 生成 .env"
    fi

    init_system
    install_docker
    configure_docker_mirrors
    install_nginx
    install_certbot
    setup_firewall_base

    # 配置 SSH 公钥认证（若 .env 中设置了 SSH_PUBLIC_KEY）
    if [ -n "${SSH_PUBLIC_KEY:-}" ]; then
        setup_ssh_key "$SSH_PUBLIC_KEY"
    fi

    echo ""
    log "===== 基础环境安装完成 ====="
    log "已安装: Docker $(docker --version 2>/dev/null | grep -o '[0-9.]*' | head -1)"
    log "已安装: Docker Compose $(docker compose version --short 2>/dev/null)"
    log "已安装: Nginx $(nginx -v 2>&1 | grep -o '[0-9.]*')"
    log "已安装: Certbot $(certbot --version 2>&1 | grep -o '[0-9.]*')"
    echo ""
    log "接下来可以部署各服务:"
    log "  Gitea:       cd /opt/gitea && bash deploy.sh"
    log "  Certd:       cd /opt/certd && bash deploy.sh"
    log "  Vaultwarden: cd /opt/vaultwarden && bash deploy.sh"
}

# 仅直接运行时执行 main，被 source 时只加载函数
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    set -euo pipefail
    _base_main "$@"
fi
