name: 测试环境部署

on:
  push:
    branches:
      - main
      - internal
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: deploy-staging-${{ github.ref }}
  cancel-in-progress: false

env:
  REGISTRY_HOST: ${{ vars.REGISTRY_HOST || 'registry.kxsw.us' }}
  IMAGE_NAME: ${{ vars.REGISTRY_IMAGE || 'registry.kxsw.us/vpn-server' }}
  STAGING_HOST: ${{ vars.STAGING_HOST || '154.12.35.103' }}
  STAGING_DEPLOY_PATH: ${{ vars.STAGING_DEPLOY_PATH || '/opt/hifast-server' }}
  STAGING_HEALTHCHECK_URL: ${{ vars.STAGING_HEALTHCHECK_URL || 'http://127.0.0.1:8080/v1/common/heartbeat' }}
  # 关闭 docker/build-push-action 自动生成的英文 job summary
  # 我们用 Telegram 通知传递部署结果，不需要 GitHub Actions 页面上那段英文
  DOCKER_BUILD_SUMMARY: false

jobs:
  build-and-deploy:
    name: 构建镜像并部署到测试环境
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: 检出代码
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: 收集发布说明
        id: release-notes
        run: |
          set -euo pipefail

          if [ "${{ github.event_name }}" = "push" ] && [ "${{ github.event.before }}" != "0000000000000000000000000000000000000000" ]; then
            RANGE="${{ github.event.before }}..${{ github.sha }}"
          else
            RANGE="-5"
          fi

          NOTES="$(git log "$RANGE" --pretty=format:'- %h %s' --no-merges | head -20)"
          if [ -z "$NOTES" ]; then
            NOTES="$(git log -1 --pretty=format:'- %h %s')"
          fi

          {
            echo "notes<<EOF"
            echo "$NOTES"
            echo "EOF"
          } >> "$GITHUB_OUTPUT"

      - name: 配置 Go 环境
        uses: actions/setup-go@v6
        with:
          go-version-file: go.mod
          cache: true

      - name: 运行测试
        run: go test ./...

      - name: 配置 Docker Buildx
        uses: docker/setup-buildx-action@v4

      - name: 构建并推送镜像
        uses: docker/build-push-action@v7
        with:
          context: .
          file: ./Dockerfile
          platforms: linux/amd64
          push: true
          build-args: |
            TARGETARCH=amd64
            VERSION=${{ github.sha }}
          tags: |
            ${{ env.IMAGE_NAME }}:${{ github.sha }}
            ${{ env.IMAGE_NAME }}:staging

      - name: 上传 compose 配置
        uses: appleboy/scp-action@v1.0.0
        with:
          host: ${{ env.STAGING_HOST }}
          username: ${{ secrets.STAGING_SSH_USER }}
          password: ${{ secrets.STAGING_SSH_PASSWORD }}
          port: ${{ secrets.STAGING_SSH_PORT || 22 }}
          source: docker-compose.cloud.yml
          target: /tmp/hifast-server-deploy/

      - name: 在测试服务器上部署
        uses: appleboy/ssh-action@v1.2.5
        with:
          host: ${{ env.STAGING_HOST }}
          username: ${{ secrets.STAGING_SSH_USER }}
          password: ${{ secrets.STAGING_SSH_PASSWORD }}
          port: ${{ secrets.STAGING_SSH_PORT || 22 }}
          timeout: 300s
          command_timeout: 600s
          script: |
            set -euo pipefail

            IMAGE_NAME="${{ env.IMAGE_NAME }}"
            NEW_TAG="${{ github.sha }}"
            DEPLOY_PATH="${{ env.STAGING_DEPLOY_PATH }}"
            HEALTHCHECK_URL="${{ env.STAGING_HEALTHCHECK_URL }}"
            ROLLBACK_TAG="rollback-${NEW_TAG}"

            if command -v sudo >/dev/null 2>&1 && ! docker ps >/dev/null 2>&1; then
              SUDO="sudo"
            else
              SUDO=""
            fi

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

            compose_cmd() {
              tag="$1"
              shift
              if docker compose version >/dev/null 2>&1; then
                if [ -n "$SUDO" ]; then
                  sudo env PPANEL_SERVER_IMAGE="$IMAGE_NAME" PPANEL_SERVER_TAG="$tag" docker compose -f docker-compose.cloud.yml "$@"
                else
                  PPANEL_SERVER_IMAGE="$IMAGE_NAME" PPANEL_SERVER_TAG="$tag" docker compose -f docker-compose.cloud.yml "$@"
                fi
              else
                if [ -n "$SUDO" ]; then
                  sudo env PPANEL_SERVER_IMAGE="$IMAGE_NAME" PPANEL_SERVER_TAG="$tag" docker-compose -f docker-compose.cloud.yml "$@"
                else
                  PPANEL_SERVER_IMAGE="$IMAGE_NAME" PPANEL_SERVER_TAG="$tag" docker-compose -f docker-compose.cloud.yml "$@"
                fi
              fi
            }

            health_check() {
              attempt=1
              while [ "$attempt" -le 6 ]; do
                if curl -fsS "$HEALTHCHECK_URL"; then
                  echo
                  return 0
                fi
                echo "Health check ${attempt}/6 failed; retrying in 10s..."
                attempt=$((attempt + 1))
                sleep 10
              done
              return 1
            }

            if [ -n "$SUDO" ]; then
              sudo mkdir -p "$DEPLOY_PATH"
              sudo cp /tmp/hifast-server-deploy/docker-compose.cloud.yml "$DEPLOY_PATH/docker-compose.cloud.yml"
            else
              mkdir -p "$DEPLOY_PATH"
              cp /tmp/hifast-server-deploy/docker-compose.cloud.yml "$DEPLOY_PATH/docker-compose.cloud.yml"
            fi

            cd "$DEPLOY_PATH"

            PREVIOUS_IMAGE_ID="$(docker_cmd inspect --format '{{.Image}}' ppanel-server 2>/dev/null || true)"
            echo "Previous image ID: ${PREVIOUS_IMAGE_ID:-none}"

            echo "Pulling ${IMAGE_NAME}:${NEW_TAG}"
            compose_cmd "$NEW_TAG" pull ppanel-server

            echo "Starting ppanel-server"
            compose_cmd "$NEW_TAG" up -d ppanel-server

            echo "Checking ${HEALTHCHECK_URL}"
            if health_check; then
              docker_cmd image prune -f || true
              echo "Staging deployment succeeded"
              exit 0
            fi

            echo "Health check failed; attempting rollback"
            if [ -n "$PREVIOUS_IMAGE_ID" ]; then
              docker_cmd tag "$PREVIOUS_IMAGE_ID" "${IMAGE_NAME}:${ROLLBACK_TAG}"
              compose_cmd "$ROLLBACK_TAG" up -d ppanel-server
              health_check || true
            else
              echo "No previous image found; rollback skipped"
            fi

            docker_cmd image prune -f || true
            exit 1

      - name: Telegram 成功通知
        if: success()
        env:
          TG_BOT_TOKEN: ${{ secrets.TG_BOT_TOKEN }}
          TG_CHAT_ID: ${{ secrets.TG_CHAT_ID }}
        run: |
          if [ -z "${TG_BOT_TOKEN:-}" ] || [ -z "${TG_CHAT_ID:-}" ]; then
            echo "Telegram 密钥未配置，跳过通知。"
            exit 0
          fi

          MESSAGE="$(cat <<'EOF'
          ✅ 测试环境发布成功
          仓库：${{ github.repository }}
          分支：${{ github.ref_name }}
          提交：${{ github.sha }}
          操作人：${{ github.actor }}
          镜像：${{ env.IMAGE_NAME }}:${{ github.sha }}
          本次更新：
          ${{ steps.release-notes.outputs.notes }}
          运行记录：${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
          EOF
          )"

          curl -fsS -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
            --data-urlencode "chat_id=${TG_CHAT_ID}" \
            --data-urlencode "text=${MESSAGE}" || echo "Telegram 通知发送失败，但发布结果不受影响。"

      - name: Telegram 失败通知
        if: failure()
        env:
          TG_BOT_TOKEN: ${{ secrets.TG_BOT_TOKEN }}
          TG_CHAT_ID: ${{ secrets.TG_CHAT_ID }}
        run: |
          if [ -z "${TG_BOT_TOKEN:-}" ] || [ -z "${TG_CHAT_ID:-}" ]; then
            echo "Telegram 密钥未配置，跳过通知。"
            exit 0
          fi

          MESSAGE="$(cat <<'EOF'
          ❌ 测试环境发布失败
          仓库：${{ github.repository }}
          分支：${{ github.ref_name }}
          提交：${{ github.sha }}
          操作人：${{ github.actor }}
          镜像：${{ env.IMAGE_NAME }}:${{ github.sha }}
          本次更新：
          ${{ steps.release-notes.outputs.notes }}
          运行记录：${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
          EOF
          )"

          curl -fsS -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
            --data-urlencode "chat_id=${TG_CHAT_ID}" \
            --data-urlencode "text=${MESSAGE}" || echo "Telegram 通知发送失败，工作流失败状态已记录。"
