name: PR slow CI - Suggestion
on:
  pull_request_target:
    types: [opened, synchronize, reopened]

jobs:
  get-pr-number:
    name: Get PR number
    uses: ./.github/workflows/get-pr-number.yml

  get-pr-info:
    name: Get PR commit SHA
    needs: get-pr-number
    if: ${{ needs.get-pr-number.outputs.PR_NUMBER != ''}}
    uses: ./.github/workflows/get-pr-info.yml
    with:
      pr_number: ${{ needs.get-pr-number.outputs.PR_NUMBER }}

  get-jobs:
    name: Get test files to run
    runs-on: ubuntu-22.04
    needs: [get-pr-number, get-pr-info]
    outputs:
      jobs: ${{ steps.get_jobs.outputs.jobs_to_run }}
    steps:
      # This checkout to the main branch
      - uses: actions/checkout@v4
        with:
          fetch-depth: "0"

      # We need to use `${{ ... }}` here to avoid `Argument list too long` error when a PR changes a lot of files.
      # (We could also try to use artifact approach, but it's more involved).
      # `CodeQL` doesn't identify any security issue here. Also `PR_FILES` is from `get-pr-info.yml` by using an api
      # `github.rest.pulls.listFiles`, which is fine.
      - name: Write pr_files file
        run: |
          cat > pr_files.txt << 'EOF'
          ${{ needs.get-pr-info.outputs.PR_FILES }}
          EOF

      - name: Get repository content
        id: repo_content
        uses: actions/github-script@v6
        with:
          script: |
            const fs = require('node:fs');

            const { data: tests_dir } = await github.rest.repos.getContent({
              owner: '${{ needs.get-pr-info.outputs.PR_HEAD_REPO_OWNER }}',
              repo: '${{ needs.get-pr-info.outputs.PR_HEAD_REPO_NAME }}',
              path: 'tests',
              ref: '${{ needs.get-pr-info.outputs.PR_HEAD_SHA }}',
            });

            const { data: tests_models_dir } = await github.rest.repos.getContent({
              owner: '${{ needs.get-pr-info.outputs.PR_HEAD_REPO_OWNER }}',
              repo: '${{ needs.get-pr-info.outputs.PR_HEAD_REPO_NAME }}',
              path: 'tests/models',
              ref: '${{ needs.get-pr-info.outputs.PR_HEAD_SHA }}',
            });

            const { data: tests_quantization_dir } = await github.rest.repos.getContent({
              owner: '${{ needs.get-pr-info.outputs.PR_HEAD_REPO_OWNER }}',
              repo: '${{ needs.get-pr-info.outputs.PR_HEAD_REPO_NAME }}',
              path: 'tests/quantization',
              ref: '${{ needs.get-pr-info.outputs.PR_HEAD_SHA }}',
            });

            // Write to files instead of outputs
            fs.writeFileSync('tests_dir.txt', JSON.stringify(tests_dir, null, 2));
            fs.writeFileSync('tests_models_dir.txt', JSON.stringify(tests_models_dir, null, 2));
            fs.writeFileSync('tests_quantization_dir.txt', JSON.stringify(tests_quantization_dir, null, 2));

      - name: Run script to get jobs to run
        id: get_jobs
        run: |
          python utils/get_pr_run_slow_jobs.py | tee output.txt
          echo "jobs_to_run: $(tail -n 1 output.txt)"
          echo "jobs_to_run=$(tail -n 1 output.txt)" >> $GITHUB_OUTPUT

  send_comment:
    # Will delete the previous comment and send a new one if:
    #   - either the content is changed
    #   - or the previous comment is 30 minutes or more old
    name: Send a comment to suggest jobs to run
    if: ${{ needs.get-jobs.outputs.jobs != '' }}
    needs: [get-pr-number, get-jobs]
    permissions:
      pull-requests: write
    runs-on: ubuntu-22.04
    steps:
      - name: Check and update comment if needed
        uses: actions/github-script@v7
        env:
          BODY: "\n\nrun-slow: ${{ needs.get-jobs.outputs.jobs }}"
        with:
          script: |
            const prNumber = ${{ needs.get-pr-number.outputs.PR_NUMBER }};
            const commentPrefix = "**[For maintainers]** Suggested jobs to run (before merge)";
            const thirtyMinutesAgo = new Date(Date.now() - 30 * 60 * 1000); // 30 minutes ago
            const newBody = `${commentPrefix}${process.env.BODY}`;
            
            // Get all comments on the PR
            const { data: comments } = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: prNumber
            });
            
            // Find existing comments that start with our prefix
            const existingComments = comments.filter(comment => 
              comment.user.login === 'github-actions[bot]' && 
              comment.body.startsWith(commentPrefix)
            );
            
            let shouldCreateNewComment = true;
            let commentsToDelete = [];
            
            if (existingComments.length > 0) {
              // Get the most recent comment
              const mostRecentComment = existingComments
                .sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0];
              
              const commentDate = new Date(mostRecentComment.created_at);
              const isOld = commentDate < thirtyMinutesAgo;
              const isDifferentContent = mostRecentComment.body !== newBody;
              
              console.log(`Most recent comment created: ${mostRecentComment.created_at}`);
              console.log(`Is older than 30 minutes: ${isOld}`);
              console.log(`Has different content: ${isDifferentContent}`);
              
              if (isOld || isDifferentContent) {
                // Delete all existing comments and create new one
                commentsToDelete = existingComments;
                console.log(`Will delete ${commentsToDelete.length} existing comment(s) and create new one`);
              } else {
                // Content is same and comment is recent, skip
                shouldCreateNewComment = false;
                console.log('Comment is recent and content unchanged, skipping update');
              }
            } else {
              console.log('No existing comments found, will create new one');
            }
            
            // Delete old comments if needed
            for (const comment of commentsToDelete) {
              console.log(`Deleting comment #${comment.id} (created: ${comment.created_at})`);
              await github.rest.issues.deleteComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: comment.id
              });
            }
            
            // Create new comment if needed
            if (shouldCreateNewComment) {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: prNumber,
                body: newBody
              });
              console.log('✅ New comment created');
            } else {
              console.log('ℹ️ No comment update needed');
            }