name: OpenIM Server 构建和发布

on:
  push:
    branches: [ main, master, wallet, develop, release-* ]
    paths:
      - '**'
  pull_request:
    branches: [ main, master, wallet ]
    paths:
      - '**'
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      tag:
        description: "Tag version to be used for Docker image"
        required: true
        default: "latest"

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  REGISTRY: docker.io
  DOCKER_USER: ${{ secrets.DOCKER_USERNAME || 'mag1666888' }}
  GO_VERSION: "1.24"

jobs:
  build-and-push:
    runs-on: openim
    permissions:
      contents: read
      packages: write

    steps:
    - name: 检出代码
      uses: actions/checkout@v4
      with:
        submodules: recursive

    - name: 配置 SSH 密钥
      run: |
        echo "🔑 配置 SSH 密钥..."
        # 创建 .ssh 目录
        mkdir -p ~/.ssh
        chmod 700 ~/.ssh
        
        # 从 secrets 中获取 SSH 私钥并 base64 解码
        echo "${{ secrets.SSH_PRIVATE_KEY }}" | base64 -d > ~/.ssh/id_rsa
        chmod 600 ~/.ssh/id_rsa
        
        # 配置 SSH 主机密钥验证（可选，避免首次连接时的确认提示）
        ssh-keyscan -H git.imall.cloud >> ~/.ssh/known_hosts 2>/dev/null || true
        chmod 644 ~/.ssh/known_hosts
        
        # 验证 SSH 密钥
        if [ -f ~/.ssh/id_rsa ]; then
          echo "✅ SSH 密钥配置成功"
        else
          echo "❌ SSH 密钥配置失败"
          exit 1
        fi

    - name: 检出 protocol 仓库
      run: |
        echo "📦 克隆 protocol 仓库..."
        # 使用 SSH 方式克隆 protocol 仓库
        git clone git@git.imall.cloud:openim/protocol.git ./protocol || true
        cd ./protocol
        git fetch --all
        git checkout v1.0.4
        cd ..
        # 创建父目录的protocol符号链接，使replace ../protocol 能正确找到
        ln -sf $PWD/protocol ../protocol || true
        echo "✅ protocol 仓库检出完成"

    - name: 设置 Go 缓存
      uses: actions/cache@v4
      with:
        path: |
          ~/.cache/go-build
          ~/go/pkg/mod
        key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
        restore-keys: |
          ${{ runner.os }}-go-

    - name: 设置 Go 环境
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true

    - name: 检查 Go 环境
      run: |
        if command -v go &> /dev/null; then
          echo "Go: $(go version)"
          go mod verify >/dev/null 2>&1
          go mod tidy >/dev/null 2>&1
          go mod download >/dev/null 2>&1
          echo "Go modules verified"
        else
          echo "Go not found, skipping Go steps"
        fi

    - name: 检查系统资源
      run: |
        echo "系统资源信息:"
        echo "CPU核心数: $(nproc)"
        echo "内存总量: $(free -h | awk '/^Mem:/ {print $2}')"
        echo "可用内存: $(free -h | awk '/^Mem:/ {print $7}')"
        echo "磁盘空间: $(df -h / | awk 'NR==2 {print $4}')"
        echo ""

    - name: 清理 Docker 环境
      run: |
        echo "清理Docker环境..."
        docker image prune -f >/dev/null 2>&1 || true

    - name: 登录到 Docker Hub
      uses: docker/login-action@v3.3.0
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}

    - name: 设置 Docker Buildx
      uses: docker/setup-buildx-action@v3.8.0
      with:
        driver-opts: |
          image=moby/buildkit:buildx-stable-1
          network=host

    - name: 构建和推送所有服务镜像
      working-directory: ${{ github.workspace }}
      run: |
        # 设置错误处理
        trap 'echo "脚本在行 $LINENO 处失败，退出状态: $?"' ERR
        set -e
        
        # 获取版本标签（使用分支名）
        if [ "${{ github.event_name }}" = "release" ]; then
          VERSION_TAG="${{ github.event.release.tag_name }}"
        elif [ -n "${{ github.event.inputs.tag }}" ]; then
          VERSION_TAG="${{ github.event.inputs.tag }}"
        else
          # 使用分支名作为标签
          VERSION_TAG="${{ github.ref_name }}"
        fi
        
        echo "构建OpenIM Server镜像 (标签: $VERSION_TAG)"
        echo "Docker用户: $DOCKER_USER"
        
        # 定义构建顺序（openim-msggateway 和 openim-push 优先构建）
        CORE_SERVICES=(
          "openim-msggateway"
          "openim-push"
          "openim-rpc-msg"
          "openim-api"
          "openim-msgtransfer"
          "openim-crontask"
        )
        
        RPC_SERVICES=(
          "openim-rpc-auth"
          "openim-rpc-user"
          "openim-rpc-friend"
          "openim-rpc-group"
          "openim-rpc-conversation"
          "openim-rpc-third"
        )
        
        # 构建函数
        build_service() {
            local service=$1
            local dockerfile="build/images/$service/Dockerfile"
            local start_time=$(date +%s)
            
            if [ -f "$dockerfile" ]; then
                echo "📦 构建 $service..."
                
                if docker buildx build \
                  --platform linux/amd64 \
                  --file "$dockerfile" \
                  --tag "$DOCKER_USER/$service:$VERSION_TAG" \
                  --tag "$DOCKER_USER/$service:prod" \
                  --push \
                  --progress=plain \
                  --cache-from type=gha,scope=openim-build-${{ github.ref_name }}-$service \
                  --cache-to type=gha,mode=max,scope=openim-build-${{ github.ref_name }}-$service \
                  --build-arg BUILDKIT_INLINE_CACHE=1 \
                  --build-arg GOCACHE=/go-cache \
                  --build-arg GOMAXPROCS=$(nproc) \
                  --provenance=false \
                  --sbom=false \
                  . > "/tmp/build_${service}.log" 2>&1; then
                    
                    local end_time=$(date +%s)
                    local duration=$((end_time - start_time))
                    echo "✅ $service 构建成功 (${duration}秒)"
                else
                    echo "❌ $service 构建失败，查看详细错误日志:"
                    echo "=========================================="
                    cat "/tmp/build_${service}.log"
                    echo "=========================================="
                    echo "最后 50 行错误日志:"
                    tail -50 "/tmp/build_${service}.log"
                    return 1
                fi
            else
                echo "❌ $service - 未找到 Dockerfile: $dockerfile"
                return 1
            fi
        }
        
        # 初始化构建统计
        failed_services=()
        successful_services=()
        
        # 计算总服务数
        total_services=$((${#CORE_SERVICES[@]} + ${#RPC_SERVICES[@]}))
        echo "开始构建 $total_services 个服务..."
        
        # 先构建核心服务
        for service in "${CORE_SERVICES[@]}"; do
            if build_service "$service"; then
                successful_services+=("$service")
            else
                failed_services+=("$service")
            fi
        done
        
        # 构建RPC服务
        for service in "${RPC_SERVICES[@]}"; do
            if build_service "$service"; then
                successful_services+=("$service")
            else
                failed_services+=("$service")
            fi
        done
        
        # 输出构建结果统计
        echo ""
        echo "🎉 构建完成总结"
        echo "✅ 成功构建: ${#successful_services[@]} 个服务"
        echo "❌ 构建失败: ${#failed_services[@]} 个服务"
        echo "📊 成功率: $(( ${#successful_services[@]} * 100 / total_services ))%"
        
        if [ ${#failed_services[@]} -gt 0 ]; then
            echo ""
            echo "失败服务错误日志:"
            for service in "${failed_services[@]}"; do
                echo "=== $service ==="
                cat "/tmp/build_${service}.log" 2>/dev/null || echo "无法读取日志文件"
                echo ""
            done
            exit 1
        fi

    - name: 配置 kubectl
      if: success()
      run: |
        echo "🔧 配置 kubectl 连接到阿里云 ACK..."
        # 创建 kubeconfig 目录
        mkdir -p ~/.kube
        
        # 从 secrets 中获取 kubeconfig 内容并处理
        echo "📝 处理 kubeconfig 文件..."
        
        # 直接解码 base64 内容
        echo "🔍 解码 base64 编码的 kubeconfig..."
        echo "${{ secrets.KUBECONFIG }}" | base64 -d > ~/.kube/config
        
        # 验证解码是否成功
        if [ ! -s ~/.kube/config ]; then
          echo "❌ kubeconfig 解码失败或文件为空"
          exit 1
        fi
        
        # 显示 kubeconfig 内容供手动检查
        echo "🔍 解码后的 kubeconfig 内容："
        cat ~/.kube/config
        
        chmod 600 ~/.kube/config
        echo "✅ kubeconfig 配置完成"
        
        # 详细验证 kubectl 配置
        echo "🔍 验证 kubectl 配置..."
        echo "当前上下文:"
        kubectl config current-context 2>&1 || echo "无法获取当前上下文"
        
        echo "可用上下文:"
        kubectl config get-contexts 2>&1 || echo "无法获取上下文列表"
        
        echo "集群信息:"
        kubectl cluster-info 2>&1 || echo "无法获取集群信息"
        
        echo "API 版本:"
        kubectl version --short 2>&1 || echo "无法获取版本信息"

    - name: 部署到阿里云 ACK
      if: success()
      run: |
        echo "🚀 开始部署到阿里云 ACK..."
        
        # 简单验证 kubectl
        if ! kubectl version --client >/dev/null 2>&1; then
          echo "❌ kubectl 不可用，跳过部署步骤"
          exit 0
        fi
        
        echo "✅ kubectl 可用，尝试部署..."
        
        # 获取版本标签（使用分支名）
        if [ "${{ github.event_name }}" = "release" ]; then
          VERSION_TAG="${{ github.event.release.tag_name }}"
        elif [ -n "${{ github.event.inputs.tag }}" ]; then
          VERSION_TAG="${{ github.event.inputs.tag }}"
        else
          # 使用分支名作为标签
          VERSION_TAG="${{ github.ref_name }}"
        fi
        
        echo "版本标签: $VERSION_TAG"
        echo "Docker用户: $DOCKER_USER"
        
        # 检查部署文件是否存在
        DEPLOY_DIR="deployments/deploy"
        if [ ! -d "$DEPLOY_DIR" ]; then
          echo "❌ 部署目录不存在: $DEPLOY_DIR"
          echo "📁 当前目录内容:"
          ls -la
          echo "⚠️ 部署失败，但构建流程继续"
          exit 0
        fi
        
        echo "📁 进入部署目录: $DEPLOY_DIR"
        cd "$DEPLOY_DIR"
        
        # 设置命名空间
        NS=${NS:-default}
        echo "使用命名空间: $NS"
        
        # 创建命名空间（如果不存在）
        kubectl get ns "$NS" >/dev/null 2>&1 || kubectl create ns "$NS"
        kubectl config set-context --current --namespace="$NS"
        
        # 尝试部署，如果失败则继续
        echo "🚀 开始部署OpenIM Server服务..."
        
        # 定义所有部署文件
        DEPLOYMENT_FILES=(
          "openim-api-deployment.yml"
          "openim-crontask-deployment.yml"
          "openim-rpc-user-deployment.yml"
          "openim-msggateway-deployment.yml"
          "openim-push-deployment.yml"
          "openim-msgtransfer-deployment.yml"
          "openim-rpc-conversation-deployment.yml"
          "openim-rpc-auth-deployment.yml"
          "openim-rpc-group-deployment.yml"
          "openim-rpc-friend-deployment.yml"
          "openim-rpc-msg-deployment.yml"
          "openim-rpc-third-deployment.yml"
        )
        
        # 更新镜像标签并部署
        DEPLOYMENT_ERRORS=()
        for file in "${DEPLOYMENT_FILES[@]}"; do
          if [ -f "$file" ]; then
            echo "📦 处理 $file..."
            # 备份原文件（保留 imagePullSecrets 等配置）
            cp "$file" "$file.bak"
            # 更新镜像标签（替换用户名和标签，但保留 imagePullSecrets）
            sed -i "s|image: .*/openim-|image: $DOCKER_USER/openim-|g" "$file"
            sed -i "s|:prod|:prod|g" "$file"
            # 验证 imagePullSecrets 是否保留
            if ! grep -q "imagePullSecrets:" "$file"; then
              echo "⚠️ 警告: $file 中缺少 imagePullSecrets，从备份恢复..."
              cp "$file.bak" "$file"
              # 只更新镜像，不修改其他内容
              sed -i "s|image: .*/openim-|image: $DOCKER_USER/openim-|g" "$file"
              sed -i "s|:prod|:prod|g" "$file"
            fi
            # 应用文件并捕获详细错误
            echo "🔍 执行: kubectl apply -f $file"
            if kubectl apply -f "$file" 2>&1; then
              echo "✅ $file 部署成功"
            else
              ERROR_OUTPUT=$(kubectl apply -f "$file" 2>&1)
              echo "❌ $file 部署失败:"
              echo "$ERROR_OUTPUT"
              DEPLOYMENT_ERRORS+=("$file: $ERROR_OUTPUT")
              echo "⚠️ 继续处理下一个文件..."
            fi
            # 清理备份文件
            rm -f "$file.bak"
          else
            echo "⚠️ $file 不存在，跳过"
          fi
        done
        
        # 显示部署错误总结
        if [ ${#DEPLOYMENT_ERRORS[@]} -gt 0 ]; then
          echo ""
          echo "🚨 部署错误总结:"
          echo "=========================================="
          for error in "${DEPLOYMENT_ERRORS[@]}"; do
            echo "❌ $error"
          done
          echo "=========================================="
        fi
        
        echo "✅ 部署步骤完成"
        
        # 强制重启所有部署以使用新镜像
        echo "🔄 强制重启所有部署以使用新镜像..."
        DEPLOYMENTS=(
          "openim-api"
          "openim-crontask" 
          "messagegateway-rpc-server"
          "openim-msgtransfer-server"
          "push-rpc-server"
          "auth-rpc-server"
          "user-rpc-server"
          "friend-rpc-server"
          "group-rpc-server"
          "conversation-rpc-server"
          "third-rpc-server"
          "msg-rpc-server"
        )
        
        for deployment in "${DEPLOYMENTS[@]}"; do
          echo "🔄 重启部署: $deployment"
          # 先删除 pod 以强制拉取新镜像（即使 imagePullPolicy 是 Always，有时也需要删除 pod）
          if kubectl delete pods -l app="$deployment" --grace-period=0 --force 2>&1; then
            echo "✅ $deployment Pod 已删除，将重新创建并拉取新镜像"
          fi
          # 然后重启 deployment
          if kubectl rollout restart deployment "$deployment" 2>&1; then
            echo "✅ $deployment 重启成功"
          else
            echo "⚠️ $deployment 重启失败，可能不存在"
          fi
        done
        
        echo "⏳ 等待部署完成..."
        for deployment in "${DEPLOYMENTS[@]}"; do
          echo "⏳ 等待 $deployment 就绪..."
          if kubectl rollout status deployment "$deployment" --timeout=300s; then
            echo "✅ $deployment 部署完成"
          else
            echo "⚠️ $deployment 超时，检查Pod状态..."
            echo "Pod状态:"
            kubectl get pods -l app="$deployment" 2>&1 || echo "无法获取Pod状态"
            echo "Pod事件:"
            kubectl get events --field-selector involvedObject.name="$deployment" --sort-by='.lastTimestamp' 2>&1 | tail -10 || echo "无法获取事件"
            echo "部署详情:"
            kubectl describe deployment "$deployment" 2>&1 | tail -20 || echo "无法获取部署详情"
          fi
        done

    - name: 验证部署状态
      if: success()
      run: |
        echo "🔍 验证部署状态..."
        
        # 详细检查集群连接和权限
        echo "🔍 检查集群连接..."
        if kubectl cluster-info 2>&1; then
          echo "✅ 集群连接正常"
        else
          CLUSTER_ERROR=$(kubectl cluster-info 2>&1)
          echo "❌ 集群连接失败: $CLUSTER_ERROR"
        fi
        
        echo "🔍 检查命名空间权限..."
        if kubectl get namespaces 2>&1; then
          echo "✅ 命名空间权限正常"
        else
          NS_ERROR=$(kubectl get namespaces 2>&1)
          echo "❌ 命名空间权限不足: $NS_ERROR"
        fi
        
        echo "🔍 检查 Pod 状态..."
        if kubectl get pods -l app=openim 2>&1; then
          echo "✅ Pod 状态检查完成"
        else
          POD_ERROR=$(kubectl get pods -l app=openim 2>&1)
          echo "❌ Pod 状态检查失败: $POD_ERROR"
        fi
        
        echo "🔍 检查部署状态..."
        if kubectl get deployments -l app=openim 2>&1; then
          echo "✅ 部署状态检查完成"
        else
          DEPLOY_ERROR=$(kubectl get deployments -l app=openim 2>&1)
          echo "❌ 部署状态检查失败: $DEPLOY_ERROR"
        fi
        
        echo "✅ 验证完成"

    - name: 生成构建报告
      run: |
        # 获取版本标签（使用分支名）
        if [ "${{ github.event_name }}" = "release" ]; then
          VERSION_TAG="${{ github.event.release.tag_name }}"
        elif [ -n "${{ github.event.inputs.tag }}" ]; then
          VERSION_TAG="${{ github.event.inputs.tag }}"
        else
          # 使用分支名作为标签
          VERSION_TAG="${{ github.ref_name }}"
        fi
        
        echo "## OpenIM Server Build Complete" >> $GITHUB_STEP_SUMMARY
        echo "**Tag:** $VERSION_TAG" >> $GITHUB_STEP_SUMMARY
        echo "**Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
        echo "**Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
        echo "**Platform:** linux/amd64" >> $GITHUB_STEP_SUMMARY
        echo "**Mode:** 完整构建和部署" >> $GITHUB_STEP_SUMMARY
        echo "" >> $GITHUB_STEP_SUMMARY
        echo "**Images:**" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-api:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-msggateway:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-msgtransfer:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-push:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-crontask:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-rpc-auth:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-rpc-user:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-rpc-friend:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-rpc-group:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-rpc-conversation:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-rpc-third:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
        echo "- \`$DOCKER_USER/openim-rpc-msg:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY