name: Build docker and publish
run-name: 简化的Docker构建和部署流程

on:
  push:
    branches:
      - main
      - internal
  pull_request:
    branches:
      - main
      - internal

env:
  # Docker镜像仓库
  REPO: ${{ vars.REPO || 'registry.kxsw.us/vpn-server' }}
  # SSH连接信息 (根据分支自动选择服务器和用户)
  SSH_HOST: ${{ github.ref_name == 'main' && vars.SSH_HOST || vars.DEV_SSH_HOST }}
  SSH_PORT: ${{ vars.SSH_PORT }}
  SSH_USER: ${{ github.ref_name == 'main' && 'ubuntu' || 'root' }}
  # SSH私钥（Gitea Secret 名称：AWS）
  SSH_KEY: ${{ secrets.AWS }}
  # TG通知
  TG_BOT_TOKEN: ${{ secrets.TG_BOT_TOKEN }}
  TG_CHAT_ID: ${{ secrets.TG_CHAT_ID }}
  # Go构建变量
  SERVICE: vpn
  SERVICE_STYLE: vpn
  VERSION: ${{ github.sha }}
  BUILDTIME: ${{ github.event.head_commit.timestamp }}
  GOARCH: amd64

jobs:
  build:
    runs-on: ario-server
    container:
      image: node:20
    strategy:
      matrix:
        # 只有node支持版本号别名
        node: ['20.15.1']
    steps:
      # 步骤1: 下载代码
      - name: 📥 下载代码
        uses: actions/checkout@v4

      # 步骤2: 设置动态环境变量
      - name: ⚙️ 设置动态环境变量
        run: |
          if [ "${{ github.ref_name }}" = "main" ]; then
            echo "DOCKER_TAG_SUFFIX=latest" >> $GITHUB_ENV
            echo "CONTAINER_NAME=ppanel-server" >> $GITHUB_ENV
            echo "DEPLOY_PATH=/opt/ppanel" >> $GITHUB_ENV
            echo "DEPLOY_ENV_LABEL=🚀 服务已成功部署到生产环境" >> $GITHUB_ENV
            echo "为 main 分支设置生产环境变量"
          elif [ "${{ github.ref_name }}" = "internal" ]; then
            echo "DOCKER_TAG_SUFFIX=internal" >> $GITHUB_ENV
            echo "CONTAINER_NAME=ppanel-server-internal" >> $GITHUB_ENV
            echo "DEPLOY_PATH=/root/bindbox" >> $GITHUB_ENV
            echo "DEPLOY_ENV_LABEL=🧪 服务已成功部署到测试环境" >> $GITHUB_ENV
            echo "为 internal 分支设置开发环境变量"
          else
            echo "DOCKER_TAG_SUFFIX=${{ github.ref_name }}" >> $GITHUB_ENV
            echo "CONTAINER_NAME=ppanel-server-${{ github.ref_name }}" >> $GITHUB_ENV
            echo "DEPLOY_PATH=/root/vpn_server_other" >> $GITHUB_ENV
            echo "DEPLOY_ENV_LABEL=🔧 服务已成功部署到其他环境" >> $GITHUB_ENV
            echo "为其他分支 (${{ github.ref_name }}) 设置环境变量"
          fi

      # 步骤3: 安装系统工具 (curl, jq) 并升级 Docker CLI 到 1.44+
      - name: 🔧 安装系统工具并升级 Docker CLI
        run: |
          set -e
          export DEBIAN_FRONTEND=noninteractive
          echo "等待 apt/dpkg 锁释放 (unattended-upgrades)..."
          end=$((SECONDS+300))
          while true; do
            LOCKS_BUSY=0
            if pgrep -x unattended-upgrades >/dev/null 2>&1; then LOCKS_BUSY=1; fi
            if command -v fuser >/dev/null 2>&1; then
              if fuser /var/lib/dpkg/lock >/dev/null 2>&1 \
                || fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 \
                || fuser /var/lib/apt/lists/lock >/dev/null 2>&1; then
                LOCKS_BUSY=1
              fi
            fi
            if [ "$LOCKS_BUSY" -eq 0 ]; then break; fi
            if [ $SECONDS -ge $end ]; then
              echo "等待 apt/dpkg 锁超时，使用 Dpkg::Lock::Timeout 继续..."
              break
            fi
            echo "仍在等待锁释放..."; sleep 5
          done

          # 基础工具
          apt-get update -y -o Dpkg::Lock::Timeout=600
          apt-get install -y -o Dpkg::Lock::Timeout=600 jq curl ca-certificates gnupg lsb-release

          # 移除旧版 docker.io，避免客户端过旧 (API 1.41)
          if dpkg -s docker.io >/dev/null 2>&1; then
            apt-get remove -y docker.io || true
          fi

          # 安装 Docker 官方仓库的 CLI (确保 API >= 1.44)
          distro_codename=$(. /etc/os-release && echo "$VERSION_CODENAME")
          install_repo="deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian ${distro_codename} stable"
          mkdir -p /etc/apt/keyrings
          curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
          echo "$install_repo" > /etc/apt/sources.list.d/docker.list
          apt-get update -y -o Dpkg::Lock::Timeout=600
          apt-get install -y -o Dpkg::Lock::Timeout=600 docker-ce-cli docker-buildx-plugin

          # 版本检查
          docker --version || true
          docker version || true
          echo "客户端 API 版本:" $(docker version --format '{{.Client.APIVersion}}')

      # 步骤4: 构建镜像
      - name: 🏗️ 构建镜像
        run: |
          echo "开始构建镜像..."
          echo "仓库: ${{ env.REPO }}"
          echo "版本标签: ${{ env.VERSION }}"
          echo "分支标签: ${{ env.DOCKER_TAG_SUFFIX }}"

          BUILD_TAG_ARGS="-t ${{ env.REPO }}:${{ env.VERSION }}"
          if [ "${{ github.event_name }}" = "push" ]; then
            BUILD_TAG_ARGS="$BUILD_TAG_ARGS -t ${{ env.REPO }}:${{ env.DOCKER_TAG_SUFFIX }}"
          else
            echo "PR事件仅构建版本标签，不推送镜像、不部署"
          fi

          docker build -f Dockerfile \
            --platform linux/amd64 \
            --build-arg TARGETARCH=amd64 \
            --build-arg VERSION=${{ env.VERSION }} \
            --build-arg BUILDTIME=${{ env.BUILDTIME }} \
            $BUILD_TAG_ARGS \
            .

          echo "镜像构建完成"

      # 步骤5: 发布到镜像仓库
      - name: 📤 发布到镜像仓库
        if: github.event_name == 'push'
        run: |
          echo "开始推送镜像..."

          echo "推送版本标签镜像: ${{ env.REPO }}:${{ env.VERSION }}"
          docker push ${{ env.REPO }}:${{ env.VERSION }}

          echo "推送分支标签镜像: ${{ env.REPO }}:${{ env.DOCKER_TAG_SUFFIX }}"
          docker push ${{ env.REPO }}:${{ env.DOCKER_TAG_SUFFIX }}

          echo "镜像推送完成"

      # 步骤6: 调试 - 打印部署目标（不输出敏感信息）
      - name: 🔍 调试 - 打印部署目标
        if: github.event_name == 'push'
        run: |
          echo "========== 部署目标调试 =========="
          echo "当前分支: ${{ github.ref_name }}"
          echo "SSH_HOST: ${{ env.SSH_HOST }}"
          echo "SSH_PORT: ${{ env.SSH_PORT }}"
          echo "SSH_USER: ${{ env.SSH_USER }}"
          echo "SSH认证方式: 私钥 (AWS)"
          echo "DEPLOY_PATH: ${{ env.DEPLOY_PATH }}"
          echo "====================================="

      # 步骤7: 传输配置文件
      - name: 📂 传输配置文件
        if: github.event_name == 'push'
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ env.SSH_HOST }}
          username: ${{ env.SSH_USER }}
          key: ${{ env.SSH_KEY }}
          port: ${{ env.SSH_PORT }}
          source: "docker-compose.cloud.yml"
          target: "/tmp/ppanel-deploy/"

      # 步骤8: 连接服务器更新、健康检查并按需回滚
      - name: 🚀 连接服务器更新并启动
        if: github.event_name == 'push'
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ env.SSH_HOST }}
          username: ${{ env.SSH_USER }}
          key: ${{ env.SSH_KEY }}
          port: ${{ env.SSH_PORT }}
          timeout: 300s
          command_timeout: 600s
          script: |
            set -e

            echo "连接服务器成功，开始部署..."
            echo "部署目录: ${{ env.DEPLOY_PATH }}"
            echo "部署标签: ${{ env.DOCKER_TAG_SUFFIX }}"
            echo "登录用户: ${{ env.SSH_USER }}"

            HEALTHCHECK_URL="http://127.0.0.1:8080/v1/common/heartbeat"
            NEW_TAG="${{ env.DOCKER_TAG_SUFFIX }}"
            ROLLBACK_TAG="rollback-${{ env.VERSION }}"
            SUDO=""
            if [ "${{ github.ref_name }}" = "main" ]; then
              SUDO="sudo"
            fi

            docker_cmd() {
              if [ -n "$SUDO" ]; then
                sudo docker "$@"
              else
                docker "$@"
              fi
            }

            compose_with_tag() {
              tag="$1"
              shift
              if [ -n "$SUDO" ]; then
                sudo env PPANEL_SERVER_TAG="$tag" docker-compose -f docker-compose.cloud.yml "$@"
              else
                PPANEL_SERVER_TAG="$tag" docker-compose -f docker-compose.cloud.yml "$@"
              fi
            }

            write_previous_tag() {
              if [ -n "$SUDO" ]; then
                printf '%s\n' "${PREVIOUS_IMAGE_TAG:-}" | sudo tee .previous-ppanel-image-tag >/dev/null
              else
                printf '%s\n' "${PREVIOUS_IMAGE_TAG:-}" > .previous-ppanel-image-tag
              fi
            }

            health_check() {
              attempt=1
              while [ "$attempt" -le 3 ]; do
                if curl -sf "$HEALTHCHECK_URL"; then
                  echo
                  return 0
                fi

                echo "健康检查第 ${attempt}/3 次失败，10s 后重试..."
                attempt=$((attempt + 1))
                sleep 10
              done

              return 1
            }

            if [ "${{ github.ref_name }}" = "main" ]; then
              sudo mkdir -p ${{ env.DEPLOY_PATH }}
              sudo cp /tmp/ppanel-deploy/docker-compose.cloud.yml ${{ env.DEPLOY_PATH }}/docker-compose.cloud.yml
            else
              mkdir -p ${{ env.DEPLOY_PATH }}
              cp /tmp/ppanel-deploy/docker-compose.cloud.yml ${{ env.DEPLOY_PATH }}/docker-compose.cloud.yml
            fi

            cd ${{ env.DEPLOY_PATH }}

            PREVIOUS_IMAGE_TAG="$(docker_cmd inspect --format '{{.Config.Image}}' ppanel-server 2>/dev/null || true)"
            PREVIOUS_IMAGE_ID="$(docker_cmd inspect --format '{{.Image}}' ppanel-server 2>/dev/null || true)"
            echo "上一版本镜像tag: ${PREVIOUS_IMAGE_TAG:-未发现}"
            echo "上一版本镜像ID: ${PREVIOUS_IMAGE_ID:-未发现}"
            write_previous_tag

            echo "📥 拉取镜像: ${{ env.REPO }}:${NEW_TAG}"
            compose_with_tag "$NEW_TAG" pull ppanel-server
            echo "🚀 启动服务..."
            compose_with_tag "$NEW_TAG" up -d ppanel-server

            echo "🩺 部署后健康检查: ${HEALTHCHECK_URL}"
            if health_check; then
              docker_cmd image prune -f || true
              echo "✅ 部署后健康检查通过"
              echo "✅ 部署命令执行完成"
              exit 0
            fi

            echo "❌ 部署后健康检查连续 3 次失败，开始回滚..."
            if [ -n "$PREVIOUS_IMAGE_ID" ]; then
              docker_cmd tag "$PREVIOUS_IMAGE_ID" "${{ env.REPO }}:${ROLLBACK_TAG}"
              echo "回滚镜像tag: ${{ env.REPO }}:${ROLLBACK_TAG}"
              compose_with_tag "$ROLLBACK_TAG" up -d ppanel-server

              echo "🩺 回滚后健康检查: ${HEALTHCHECK_URL}"
              if health_check; then
                echo "✅ 回滚后健康检查通过"
              else
                echo "❌ 回滚后健康检查仍失败"
              fi
            else
              echo "未找到上一版本镜像ID，无法自动回滚"
            fi

            docker_cmd image prune -f || true
            exit 1

      # 步骤9: TG通知 (成功)
      - name: 📱 发送成功通知到Telegram
        if: success() && github.event_name == 'push'
        uses: appleboy/telegram-action@master
        with:
          token: ${{ env.TG_BOT_TOKEN }}
          to: ${{ env.TG_CHAT_ID }}
          message: |
            ✅ 部署成功！

            📦 项目: ${{ github.repository }}
            🌿 分支: ${{ github.ref_name }}
            📝 提交: ${{ github.sha }}
            👤 提交者: ${{ github.actor }}
            🕐 时间: ${{ github.event.head_commit.timestamp }}

            ${{ env.DEPLOY_ENV_LABEL }}
            🩺 健康检查: 通过 (http://127.0.0.1:8080/v1/common/heartbeat)
          parse_mode: Markdown

      # 步骤10: TG通知 (失败)
      - name: 📱 发送失败通知到Telegram
        if: failure() && github.event_name == 'push'
        uses: appleboy/telegram-action@master
        with:
          token: ${{ env.TG_BOT_TOKEN }}
          to: ${{ env.TG_CHAT_ID }}
          message: |
            ❌ 部署失败！

            📦 项目: ${{ github.repository }}
            🌿 分支: ${{ github.ref_name }}
            📝 提交: ${{ github.sha }}
            👤 提交者: ${{ github.actor }}
            🕐 时间: ${{ github.event.head_commit.timestamp }}

            🩺 健康检查: 失败或未完成；若新版本健康检查连续 3 次失败，已自动尝试回滚并重新检查
            ⚠️ 请检查构建日志获取详细信息
          parse_mode: Markdown
