#!/usr/bin/env bash
set -euo pipefail

# ============================================
# Gitea 全新服务器一键部署脚本
# 适用于 Ubuntu 20.04+ / Debian 11+
# 包含：系统更新 → Docker → Nginx → Certbot → Gitea + MySQL
# ============================================

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

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}"; }

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

# ===== 1. 系统初始化 =====
init_system() {
    step "1/8 系统初始化"

    # 检测包管理器
    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

    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 镜像加速 =====
configure_docker_mirrors() {
    local mirrors="${DOCKER_REGISTRY_MIRRORS:-}"
    if [ -z "$mirrors" ]; then
        log "未配置 DOCKER_REGISTRY_MIRRORS，跳过镜像加速"
        return
    fi

    mkdir -p /etc/docker

    # 将逗号分隔的镜像列表转为 JSON 数组
    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
        # 生成或覆盖 daemon.json（保留 log 配置）
        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/^/  → /'
        # 重启 Docker 使配置生效
        systemctl restart docker
        log "Docker 已重启以应用镜像加速"
    else
        log "Docker 镜像加速已存在，跳过"
    fi
}

# ===== 2. 安装 Docker =====
install_docker() {
    step "2/8 安装 Docker"

    if command -v docker &> /dev/null; then
        log "Docker 已安装: $(docker --version)"
    else
        log "正在安装 Docker (使用阿里云镜像)..."
        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
        log "Docker 安装完成: $(docker --version)"
    fi

    # 确保 Docker 服务运行
    systemctl enable --now docker
    log "Docker 服务已启动"

    # 检查 Docker Compose V2
    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)"
}

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

    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|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
                $PKG_MGR install -y -q nginx
                ;;
        esac
        log "Nginx 安装完成"
    fi

    systemctl enable --now nginx

    # 确保 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 配置就绪"
}

# ===== 4. 初始化 .env =====
init_env() {
    step "4/8 初始化配置"

    if [ ! -f .env ]; then
        if [ ! -f .env.example ]; then
            error "缺少 .env.example 模板文件"
            exit 1
        fi
        cp .env.example .env

        # 自动生成随机密码
        DB_PASS=$(openssl rand -base64 24 | tr -d '/+=\n' | head -c 32)
        DB_ROOT_PASS=$(openssl rand -base64 24 | tr -d '/+=\n' | head -c 32)

        sed -i "s/请替换为强密码/${DB_PASS}/" .env
        sed -i "s/请替换为ROOT强密码/${DB_ROOT_PASS}/" .env

        log "已生成 .env 文件，数据库密码已随机生成"
        echo ""
        warn "┌─────────────────────────────────────────────┐"
        warn "│  请编辑 .env 文件，至少修改以下配置：        │"
        warn "│                                             │"
        warn "│  GITEA_DOMAIN=你的域名                      │"
        warn "│  CERTBOT_EMAIL=你的邮箱                     │"
        warn "│                                             │"
        warn "│  编辑命令: vi $SCRIPT_DIR/.env              │"
        warn "│  编辑完成后重新运行: bash deploy.sh          │"
        warn "└─────────────────────────────────────────────┘"
        exit 0
    fi

    # 加载并验证配置
    sed -i 's/\r$//' .env
    set -a
    source .env
    set +a

    local has_error=0

    if [[ -z "${GITEA_DOMAIN:-}" ]] || [[ "${GITEA_DOMAIN}" == "git.example.com" ]]; then
        error "请在 .env 中将 GITEA_DOMAIN 修改为你的实际域名"
        has_error=1
    fi
    if [[ -z "${CERTBOT_EMAIL:-}" ]] || [[ "${CERTBOT_EMAIL}" == "admin@example.com" ]]; then
        error "请在 .env 中将 CERTBOT_EMAIL 修改为你的实际邮箱"
        has_error=1
    fi
    if [[ "${DB_PASSWORD:-}" == *"请替换"* ]] || [[ -z "${DB_PASSWORD:-}" ]]; then
        error "DB_PASSWORD 未正确设置"
        has_error=1
    fi

    if [ "$has_error" -eq 1 ]; then
        error "请修改 .env 后重新运行: vi $SCRIPT_DIR/.env"
        exit 1
    fi

    log "配置检查通过: 域名=${GITEA_DOMAIN}"
}

# ===== 5. 创建数据目录 =====
create_dirs() {
    step "5/8 创建数据目录"

    local gitea_data="${GITEA_DATA_DIR:-/var/lib/gitea}"
    local mysql_data="${MYSQL_DATA_DIR:-/var/lib/mysql/gitea}"
    local backup_dir="${BACKUP_DIR:-/var/backups/gitea}"

    mkdir -p "$gitea_data" "$mysql_data" "$backup_dir"

    # Gitea 容器以 UID=1000 运行，确保数据目录归属正确
    chown -R 1000:1000 "$gitea_data"
    # MySQL 容器以 mysql(999) 运行
    chown -R 999:999 "$mysql_data"

    log "数据目录已就绪:"
    log "  Gitea 数据: $gitea_data"
    log "  MySQL 数据: $mysql_data"
    log "  备份目录:   $backup_dir"
}

# ===== 6. 配置防火墙 =====
setup_firewall() {
    step "6/8 配置防火墙"

    local ssh_port="${SSH_PORT:-2222}"

    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 allow "$ssh_port"/tcp comment "Gitea SSH" 2>/dev/null || true
        ufw reload 2>/dev/null || true
        log "UFW 防火墙规则已添加 (22, 80, 443, $ssh_port)"
    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 --permanent --add-port="$ssh_port"/tcp 2>/dev/null || true
        firewall-cmd --reload 2>/dev/null || true
        log "Firewalld 规则已添加 (22, 80, 443, $ssh_port)"
    else
        warn "未检测到防火墙工具，请手动开放端口: 22, 80, 443, $ssh_port"
    fi
}

# ===== 7. 配置 Nginx + SSL =====
setup_ssl() {
    step "7/8 配置 HTTPS (Nginx + Let's Encrypt)"

    local domain="${GITEA_DOMAIN}"
    local email="${CERTBOT_EMAIL}"

    # 安装 certbot
    if ! command -v certbot &> /dev/null; then
        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
    fi
    log "Certbot 已就绪"

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

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

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

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

    # 申请 SSL 证书
    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 端口可从外网访问"
            error "解决后重新运行 deploy.sh"
            exit 1
        fi
        log "SSL 证书申请成功"
    else
        log "SSL 证书已存在，跳过申请"
    fi

    # 部署正式 Nginx 配置
    cp "$SCRIPT_DIR/nginx/gitea.conf" /etc/nginx/sites-available/gitea
    sed -i "s/__GITEA_DOMAIN__/${domain}/g" /etc/nginx/sites-available/gitea

    nginx -t
    systemctl reload nginx
    log "Nginx HTTPS 反向代理配置完成"

    # 设置证书自动续期
    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
}

# ===== 8. 启动服务 =====
start_services() {
    step "8/8 启动 Gitea 服务"

    log "正在拉取镜像（首次可能较慢）..."
    docker compose pull

    log "正在启动容器..."
    docker compose up -d

    log "等待 MySQL 就绪..."
    local max_wait=60
    for i in $(seq 1 $max_wait); do
        if docker compose exec -T db mysqladmin ping -h localhost -u root -p"${DB_ROOT_PASSWORD}" --silent &> /dev/null; then
            log "MySQL 已就绪"
            break
        fi
        if [ "$i" -eq "$max_wait" ]; then
            warn "MySQL 启动超时，请检查日志: docker compose logs db"
        fi
        sleep 2
    done

    log "等待 Gitea 就绪..."
    for i in $(seq 1 30); do
        if curl -sf http://127.0.0.1:3000/api/v1/version &> /dev/null; then
            log "Gitea 启动成功！"
            break
        fi
        if [ "$i" -eq 30 ]; then
            warn "Gitea 可能仍在初始化，请稍后检查"
        fi
        sleep 2
    done
}

# ===== 输出完成信息 =====
show_info() {
    set -a
    source .env
    set +a

    echo ""
    echo -e "${GREEN}╔══════════════════════════════════════════════════════╗${NC}"
    echo -e "${GREEN}║           Gitea 部署完成！                          ║${NC}"
    echo -e "${GREEN}╠══════════════════════════════════════════════════════╣${NC}"
    echo -e "${GREEN}║${NC}"
    echo -e "${GREEN}║${NC}  Web 访问:    ${CYAN}https://${GITEA_DOMAIN}${NC}"
    echo -e "${GREEN}║${NC}  SSH 克隆:    ${CYAN}ssh://git@${GITEA_DOMAIN}:${SSH_PORT:-2222}/用户名/仓库.git${NC}"
    echo -e "${GREEN}║${NC}  HTTPS 克隆:  ${CYAN}https://${GITEA_DOMAIN}/用户名/仓库.git${NC}"
    echo -e "${GREEN}║${NC}"
    echo -e "${GREEN}║${NC}  已启用功能:"
    echo -e "${GREEN}║${NC}    ✓ HTTPS (Let's Encrypt 自动续期)"
    echo -e "${GREEN}║${NC}    ✓ Git LFS 大文件存储"
    echo -e "${GREEN}║${NC}    ✓ SSH 密钥认证"
    echo -e "${GREEN}║${NC}    ✓ GPG 签名验证"
    echo -e "${GREEN}║${NC}    ✓ MySQL 8.4 LTS 数据库"
    echo -e "${GREEN}║${NC}"
    echo -e "${GREEN}║${NC}  首次访问说明:"
    echo -e "${GREEN}║${NC}    1. 浏览器打开 https://${GITEA_DOMAIN}"
    echo -e "${GREEN}║${NC}    2. 进入安装向导（数据库配置已自动填写）"
    echo -e "${GREEN}║${NC}    3. 创建管理员账户"
    echo -e "${GREEN}║${NC}    4. 完成安装"
    echo -e "${GREEN}║${NC}"
    echo -e "${GREEN}║${NC}  常用命令:"
    echo -e "${GREEN}║${NC}    查看日志:  cd ${INSTALL_DIR:-/opt/gitea} && docker compose logs -f"
    echo -e "${GREEN}║${NC}    重启服务:  cd ${INSTALL_DIR:-/opt/gitea} && docker compose restart"
    echo -e "${GREEN}║${NC}    备份数据:  bash ${INSTALL_DIR:-/opt/gitea}/backup.sh"
    echo -e "${GREEN}║${NC}"
    echo -e "${GREEN}║${NC}  服务器目录:"
    echo -e "${GREEN}║${NC}    部署文件: ${INSTALL_DIR:-/opt/gitea}"
    echo -e "${GREEN}║${NC}    Gitea 数据: ${GITEA_DATA_DIR:-/var/lib/gitea}"
    echo -e "${GREEN}║${NC}    MySQL 数据: ${MYSQL_DATA_DIR:-/var/lib/mysql/gitea}"
    echo -e "${GREEN}║${NC}    备份目录: ${BACKUP_DIR:-/var/backups/gitea}"
    echo -e "${GREEN}║${NC}    SSL 证书: /etc/letsencrypt/live/${GITEA_DOMAIN}"
    echo -e "${GREEN}║${NC}    Nginx 配置: /etc/nginx/sites-available/gitea"
    echo -e "${GREEN}║${NC}"
    echo -e "${GREEN}╚══════════════════════════════════════════════════════╝${NC}"
    echo ""
    warn "重要：创建管理员后请编辑 .env 将 DISABLE_REGISTRATION 改为 true 并重启"
}

# ===== 主流程 =====
main() {
    echo -e "${CYAN}"
    echo "  ____  _ _"
    echo " / ___|(_) |_ ___  __ _"
    echo "| |  _ | | __/ _ \\/ _\` |"
    echo "| |_| || | ||  __/ (_| |"
    echo " \\____|_|\\__\\___|\\__,_|  Deploy Script"
    echo -e "${NC}"
    echo ""

    check_root
    init_system
    install_docker
    install_nginx
    init_env
    configure_docker_mirrors
    create_dirs
    setup_firewall
    setup_ssl
    start_services
    show_info

    log "===== 全部部署完成 ====="
}

main "$@"
