name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  NODE_VERSION: '22'

jobs:
  # ═══════════════════════════════════════════════════════════════
  # 1. Lint
  # ═══════════════════════════════════════════════════════════════

  lint:
    name: Lint
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      - run: npm ci
      - run: npx prisma generate
        env:
          DATABASE_URL: mysql://placeholder:placeholder@localhost:3306/placeholder
      - run: npm run lint

  # ═══════════════════════════════════════════════════════════════
  # 2. Test
  # ═══════════════════════════════════════════════════════════════

  test:
    name: Test
    runs-on: ubuntu-latest
    timeout-minutes: 10
    needs: lint
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      - run: npm ci
      - run: npx prisma generate
        env:
          DATABASE_URL: mysql://placeholder:placeholder@localhost:3306/placeholder
      - run: npm test -- --passWithNoTests
      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-results
          path: coverage/
          retention-days: 7

  # ═══════════════════════════════════════════════════════════════
  # 3. Build
  # ═══════════════════════════════════════════════════════════════

  build:
    name: Build
    runs-on: ubuntu-latest
    timeout-minutes: 10
    needs: test
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      - run: npm ci
      - run: npx prisma generate
        env:
          DATABASE_URL: mysql://placeholder:placeholder@localhost:3306/placeholder
      - run: npm run build
      - name: Verify dist output
        run: test -f dist/main.js && echo "Build OK"

  # ═══════════════════════════════════════════════════════════════
  # 4. Docker Build (integration test)
  # ═══════════════════════════════════════════════════════════════

  docker-build:
    name: Docker Build
    runs-on: ubuntu-latest
    timeout-minutes: 15
    needs: build
    steps:
      - uses: actions/checkout@v4
      - name: Build API image
        run: docker build -t zhixi-api:${{ github.sha }} -f Dockerfile .
      - name: Build Worker image
        run: docker build -t zhixi-worker:${{ github.sha }} -f Dockerfile.worker .

  # ═══════════════════════════════════════════════════════════════
  # 5. Deploy (main branch only)
  # ═══════════════════════════════════════════════════════════════

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    timeout-minutes: 15
    needs: docker-build
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Docker login
        uses: docker/login-action@v3
        with:
          registry: ${{ vars.DOCKER_REGISTRY }}
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push API image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: Dockerfile
          push: true
          tags: |
            ${{ vars.DOCKER_REGISTRY }}/zhixi-api:latest
            ${{ vars.DOCKER_REGISTRY }}/zhixi-api:${{ github.sha }}

      - name: Build and push Worker image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: Dockerfile.worker
          push: true
          tags: |
            ${{ vars.DOCKER_REGISTRY }}/zhixi-worker:latest
            ${{ vars.DOCKER_REGISTRY }}/zhixi-worker:${{ github.sha }}

      - name: Deploy via SSH
        id: deploy
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.DEPLOY_HOST }}
          username: ${{ secrets.DEPLOY_USER }}
          key: ${{ secrets.DEPLOY_SSH_KEY }}
          script: |
            set -e
            cd /opt/zhixi/api-server

            # Record previous image tags for rollback
            docker compose config --images | tee /tmp/zhixi_prev_images.txt

            docker compose pull
            docker compose up -d --remove-orphans
            docker compose exec -T api npx prisma migrate deploy

            # Health check with retry
            echo "Waiting for API health check..."
            for i in $(seq 1 12); do
              STATUS=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/health 2>/dev/null || echo "000")
              if [ "$STATUS" = "200" ]; then
                echo "Health check OK"
                exit 0
              fi
              echo "  attempt $i/12: HTTP $STATUS, retrying..."
              sleep 5
            done
            echo "::warning::Health check failed after 60s — manual rollback may be needed"
            echo "Previous images: $(cat /tmp/zhixi_prev_images.txt)"
            # Rollback: docker compose up -d <previous-image-tag>
