name: Deploy Preview (Command)

# Triggered by commenting "/deploy-preview" on a PR.
# Restricted to org members and collaborators. Use this to deploy
# previews for external contributor PRs that don't have secret access.

on:
  issue_comment:
    types: [created]

permissions:
  contents: read
  pull-requests: write
  deployments: write

jobs:
  check:
    name: Validate Command
    if: |
      github.event.issue.pull_request &&
      startsWith(github.event.comment.body, '/deploy-preview') &&
      (
        github.event.comment.author_association == 'MEMBER' ||
        github.event.comment.author_association == 'COLLABORATOR' ||
        github.event.comment.author_association == 'OWNER'
      )
    runs-on: ubuntu-latest
    outputs:
      sha: ${{ steps.pr.outputs.sha }}
      pr_number: ${{ steps.pr.outputs.number }}
    steps:
      - name: React to comment
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.reactions.createForIssueComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              comment_id: context.payload.comment.id,
              content: 'rocket',
            });

      - name: Get PR details
        id: pr
        uses: actions/github-script@v7
        with:
          script: |
            const pr = await github.rest.pulls.get({
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: context.issue.number,
            });
            core.setOutput('sha', pr.data.head.sha);
            core.setOutput('number', pr.data.number);

  deploy:
    name: Deploy ${{ matrix.example.name }}
    needs: check
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        example:
          - name: app-router-cloudflare
            project: app-router-cloudflare
            wrangler_config: dist/server/wrangler.json
          - name: pages-router-cloudflare
            project: pages-router-cloudflare
            wrangler_config: dist/pages_router_cloudflare/wrangler.json
          - name: app-router-playground
            project: app-router-playground
            wrangler_config: dist/server/wrangler.json
          - name: realworld-api-rest
            project: realworld-api-rest
            wrangler_config: dist/realworld_api_rest/wrangler.json
          - name: nextra-docs-template
            project: nextra-docs-template
            wrangler_config: dist/server/wrangler.json
          - name: benchmarks
            project: benchmarks
            wrangler_config: dist/server/wrangler.json
          - name: hackernews
            project: hackernews
            wrangler_config: dist/server/wrangler.json
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ needs.check.outputs.sha }}

      - uses: pnpm/action-setup@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: pnpm

      - run: pnpm install

      - name: Build vinext plugin
        run: pnpm run build

      - name: Build example
        run: pnpm exec vite build
        working-directory: examples/${{ matrix.example.name }}

      - name: Deploy Preview Version
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          workingDirectory: examples/${{ matrix.example.name }}
          command: versions upload --config ${{ matrix.example.wrangler_config }} --preview-alias pr-${{ needs.check.outputs.pr_number }}

  smoke-test:
    name: Smoke Test Previews
    needs: [check, deploy]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ needs.check.outputs.sha }}

      - name: Smoke test previews
        run: ./scripts/smoke-test.sh --preview pr-${{ needs.check.outputs.pr_number }}

  comment:
    name: Comment Preview URLs
    needs: [check, deploy]
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - name: Comment PR with preview URLs
        uses: actions/github-script@v7
        with:
          script: |
            const prNumber = ${{ needs.check.outputs.pr_number }};
            const alias = `pr-${prNumber}`;

            const examples = [
              { name: 'app-router-cloudflare', project: 'app-router-cloudflare' },
              { name: 'pages-router-cloudflare', project: 'pages-router-cloudflare' },
              { name: 'app-router-playground', project: 'app-router-playground', original: 'https://app-router.vercel.app' },
              { name: 'realworld-api-rest', project: 'realworld-api-rest' },
              { name: 'nextra-docs-template', project: 'nextra-docs-template' },
              { name: 'benchmarks', project: 'benchmarks' },
              { name: 'hackernews', project: 'hackernews', original: 'https://next-react-server-components.vercel.app' },
            ];

            const { data: comments } = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: prNumber,
            });

            const marker = '<!-- vinext-deploy-previews -->';
            const existingComment = comments.find(c => c.body?.includes(marker));

            const rows = examples
              .map(e => {
                const orig = e.original ? `[original](${e.original})` : '';
                return `| ${e.name} | [preview](https://${alias}-${e.project}.vinext.workers.dev) | [production](https://${e.project}.vinext.workers.dev) | ${orig} |`;
              })
              .join('\n');

            const body = [
              marker,
              '| Example | Preview | Production | Original |',
              '|---------|---------|------------|----------|',
              rows,
            ].join('\n');

            if (existingComment) {
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: existingComment.id,
                body,
              });
            } else {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: prNumber,
                body,
              });
            }
