name: 'Label Workstream Rollup'

on:
  issues:
    types: ['opened', 'edited', 'reopened']
  schedule:
    - cron: '0 * * * *'
  workflow_dispatch:

jobs:
  labeler:
    if: "github.repository == 'google-gemini/gemini-cli'"
    runs-on: 'ubuntu-latest'
    permissions:
      issues: 'write'
    steps:
      - name: 'Check for Parent Workstream and Apply Label'
        uses: 'actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b' # ratchet:actions/github-script@v7
        with:
          script: |
            const labelToAdd = 'workstream-rollup';

            // Allow-list of parent issue URLs
            const allowedParentUrls = [
              'https://github.com/google-gemini/gemini-cli/issues/15374',
              'https://github.com/google-gemini/gemini-cli/issues/15456',
              'https://github.com/google-gemini/gemini-cli/issues/15324',
              'https://github.com/google-gemini/gemini-cli/issues/17202',
              'https://github.com/google-gemini/gemini-cli/issues/17203'
            ];

            // Single issue processing (for event triggers)
            async function processSingleIssue(owner, repo, number) {
              const query = `
                query($owner:String!, $repo:String!, $number:Int!) {
                  repository(owner:$owner, name:$repo) {
                    issue(number:$number) {
                      number
                      parent {
                        url
                        parent {
                          url
                          parent {
                            url
                            parent {
                              url
                              parent {
                                url
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              `;
              try {
                const result = await github.graphql(query, { owner, repo, number });

                if (!result || !result.repository || !result.repository.issue) {
                  console.log(`Issue #${number} not found or data missing.`);
                  return;
                }

                const issue = result.repository.issue;
                await checkAndLabel(issue, owner, repo);
              } catch (error) {
                console.error(`Failed to process issue #${number}:`, error);
                throw error; // Re-throw to be caught by main execution
              }
            }

            // Bulk processing (for schedule/dispatch)
            async function processAllOpenIssues(owner, repo) {
              const query = `
                query($owner:String!, $repo:String!, $cursor:String) {
                  repository(owner:$owner, name:$repo) {
                    issues(first: 100, states: OPEN, after: $cursor) {
                      pageInfo {
                        hasNextPage
                        endCursor
                      }
                      nodes {
                        number
                        parent {
                          url
                          parent {
                            url
                            parent {
                              url
                              parent {
                                url
                                parent {
                                  url
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              `;

              let hasNextPage = true;
              let cursor = null;

              while (hasNextPage) {
                try {
                  const result = await github.graphql(query, { owner, repo, cursor });

                  if (!result || !result.repository || !result.repository.issues) {
                     console.error('Invalid response structure from GitHub API');
                     break;
                  }

                  const issues = result.repository.issues.nodes || [];

                  console.log(`Processing batch of ${issues.length} issues...`);
                  for (const issue of issues) {
                    await checkAndLabel(issue, owner, repo);
                  }

                  hasNextPage = result.repository.issues.pageInfo.hasNextPage;
                  cursor = result.repository.issues.pageInfo.endCursor;
                } catch (error) {
                  console.error('Failed to fetch issues batch:', error);
                  throw error; // Re-throw to be caught by main execution
                }
              }
            }

            async function checkAndLabel(issue, owner, repo) {
              if (!issue || !issue.parent) return;

              let currentParent = issue.parent;
              let tracedParents = [];
              let matched = false;

              while (currentParent) {
                tracedParents.push(currentParent.url);

                if (allowedParentUrls.includes(currentParent.url)) {
                  console.log(`SUCCESS: Issue #${issue.number} is a descendant of ${currentParent.url}. Trace: ${tracedParents.join(' -> ')}. Adding label.`);
                  await github.rest.issues.addLabels({
                    owner,
                    repo,
                    issue_number: issue.number,
                    labels: [labelToAdd]
                  });
                  matched = true;
                  break;
                }
                currentParent = currentParent.parent;
              }

              if (!matched && context.eventName === 'issues') {
                 console.log(`Issue #${issue.number} did not match any allowed workstreams. Trace: ${tracedParents.join(' -> ') || 'None'}.`);
              }
            }

            // Main execution
            try {
              if (context.eventName === 'issues') {
                console.log(`Processing single issue #${context.payload.issue.number}...`);
                await processSingleIssue(context.repo.owner, context.repo.repo, context.payload.issue.number);
              } else {
                console.log(`Running for event: ${context.eventName}. Processing all open issues...`);
                await processAllOpenIssues(context.repo.owner, context.repo.repo);
              }
            } catch (error) {
              core.setFailed(`Workflow failed: ${error.message}`);
            }
