name: deploy to staging (alpha)

on:
  push:
    branches: [main]
  workflow_dispatch:

concurrency:
  group: deploy-staging
  cancel-in-progress: false

jobs:
  test:
    name: test + lint（gate）
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v4
        with: { version: "latest", enable-cache: true }
      - run: uv sync --all-groups
      - run: uv run pytest -q
      - run: uv run ruff check src test scripts

  deploy:
    name: rsync → alpha (120.27.148.143) → restart
    needs: [test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.ALPHA_SSH_KEY }}

      - name: known_hosts
        run: |
          mkdir -p ~/.ssh
          ssh-keyscan ${{ secrets.ALPHA_HOST }} >> ~/.ssh/known_hosts

      - name: rsync 源码（保留 .env / logs / data 运行时资产）
        run: |
          rsync -az --delete \
            --exclude '.venv' --exclude '__pycache__' --exclude '.pytest_cache' \
            --exclude 'data' --exclude 'logs' --exclude '*.db*' --exclude '.git' \
            --exclude '.github' --exclude 'site' --exclude '.env' --exclude '.vault' \
            ./ root@${{ secrets.ALPHA_HOST }}:/opt/xiangqin/

      - name: 远端 mkdir + uv sync + chown
        run: |
          ssh root@${{ secrets.ALPHA_HOST }} "cd /opt/xiangqin && \
            mkdir -p /opt/xiangqin/logs /opt/xiangqin/data && \
            UV_PYTHON_INSTALL_DIR=/opt/uv-python \
            UV_PYTHON_PREFERENCE=only-managed UV_PYTHON=3.12 \
            UV_HTTP_TIMEOUT=120 \
            /root/.local/bin/uv sync --no-group dev && \
            chown -R xiangqin:xiangqin /opt/xiangqin"

      - name: 注入 staging 专属 env（测试号白名单 + 支付宝沙箱开关；prod 不注入）
        env:
          TEST_OTP: ${{ secrets.TEST_OTP_STAGING }}
        run: |
          ssh root@${{ secrets.ALPHA_HOST }} "touch /opt/xiangqin/.env && \
            sed -i '/^XIANGQIN_TEST_PHONES=/d;/^XIANGQIN_TEST_OTP=/d;/^XIANGQIN_ALIPAY_SANDBOX=/d' /opt/xiangqin/.env && \
            echo 'XIANGQIN_TEST_PHONES=13900000001,13900000002' >> /opt/xiangqin/.env && \
            echo 'XIANGQIN_TEST_OTP=$TEST_OTP' >> /opt/xiangqin/.env && \
            echo 'XIANGQIN_ALIPAY_SANDBOX=1' >> /opt/xiangqin/.env && \
            chmod 600 /opt/xiangqin/.env && \
            chown xiangqin:xiangqin /opt/xiangqin/.env"

      - name: systemd + 重启
        run: |
          ssh root@${{ secrets.ALPHA_HOST }} "cp /opt/xiangqin/systemd/xiangqin.service /etc/systemd/system/ && \
            systemctl daemon-reload && \
            systemctl enable xiangqin && \
            systemctl restart xiangqin && \
            sleep 2 && \
            systemctl is-active xiangqin"

      - name: smoke test（最多 15s 等 uvicorn ready）
        run: |
          ssh root@${{ secrets.ALPHA_HOST }} 'for i in $(seq 1 15); do \
            curl -sf http://127.0.0.1/health >/dev/null && break; sleep 1; done; \
            curl -s http://127.0.0.1/health'

      - name: E2E 冒烟（白名单注册 → 买信封 → 沙箱 qr_code）
        env:
          TEST_OTP: ${{ secrets.TEST_OTP_STAGING }}
          ALPHA_URL: http://${{ secrets.ALPHA_HOST }}
        run: |
          set -euo pipefail
          echo "→ register 13900000002"
          REQ=$(curl -sfS -X POST "$ALPHA_URL/auth/register" \
            -H 'Content-Type: application/json' \
            -d '{"phone":"13900000002"}' \
            | python3 -c "import json,sys;print(json.load(sys.stdin)['request_id'])")
          echo "  request_id=$REQ"
          echo "→ verify with TEST_OTP"
          TOKEN=$(curl -sfS -X POST "$ALPHA_URL/auth/verify" \
            -H 'Content-Type: application/json' \
            -d "{\"request_id\":\"$REQ\",\"code\":\"$TEST_OTP\"}" \
            | python3 -c "import json,sys;print(json.load(sys.stdin)['session_token'])")
          echo "  token len=${#TOKEN}"
          echo "→ envelope buy (sandbox)"
          # alipay 沙箱偶发慢/超时，retry 2 次
          QR=""
          for i in 1 2 3; do
            RESP=$(curl -sS -X POST "$ALPHA_URL/envelope/buy" \
              -H "Authorization: Bearer $TOKEN" \
              -H 'Content-Type: application/json' \
              -d '{"count":10}' 2>&1) || true
            QR=$(echo "$RESP" | python3 -c "import json,sys;d=json.load(sys.stdin);print(d.get('qr_code',''))" 2>/dev/null || echo "")
            if [ -n "$QR" ]; then break; fi
            echo "  attempt $i failed (sandbox flaky), retry in 3s..."
            sleep 3
          done
          echo "  qr_code=$QR"
          if [ -z "$QR" ]; then echo "✗ 3 次都失败"; exit 1; fi
          case "$QR" in
            https://qr*alipay.com/*|https://*alipaydev.com/*)
              echo "✓ E2E sandbox precreate 通，qr_code 格式合法" ;;
            *)
              echo "✗ qr_code 格式异常: $QR"; exit 1 ;;
          esac
