name: '🔒 Gemini Scheduled Stale Issue Closer'

on:
  schedule:
    - cron: '0 0 * * 0' # Every Sunday at midnight UTC
  workflow_dispatch:
    inputs:
      dry_run:
        description: 'Run in dry-run mode (no changes applied)'
        required: false
        default: false
        type: 'boolean'

concurrency:
  group: '${{ github.workflow }}'
  cancel-in-progress: true

defaults:
  run:
    shell: 'bash'

jobs:
  close-stale-issues:
    runs-on: 'ubuntu-latest'
    permissions:
      issues: 'write'
    steps:
      - name: 'Generate GitHub App Token'
        id: 'generate_token'
        uses: 'actions/create-github-app-token@v1'
        with:
          app-id: '${{ secrets.APP_ID }}'
          private-key: '${{ secrets.PRIVATE_KEY }}'
          permission-issues: 'write'

      - name: 'Process Stale Issues'
        uses: 'actions/github-script@v7'
        env:
          DRY_RUN: '${{ inputs.dry_run }}'
        with:
          github-token: '${{ steps.generate_token.outputs.token }}'
          script: |
            const dryRun = process.env.DRY_RUN === 'true';
            if (dryRun) {
              core.info('DRY RUN MODE ENABLED: No changes will be applied.');
            }
            const batchLabel = 'Stale';

            const threeMonthsAgo = new Date();
            threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3);

            const tenDaysAgo = new Date();
            tenDaysAgo.setDate(tenDaysAgo.getDate() - 10);

            core.info(`Cutoff date for creation: ${threeMonthsAgo.toISOString()}`);
            core.info(`Cutoff date for updates: ${tenDaysAgo.toISOString()}`);

            const query = `repo:${context.repo.owner}/${context.repo.repo} is:issue is:open created:<${threeMonthsAgo.toISOString()}`;
            core.info(`Searching with query: ${query}`);

            const itemsToCheck = await github.paginate(github.rest.search.issuesAndPullRequests, {
              q: query,
              sort: 'created',
              order: 'asc',
              per_page: 100
            });

            core.info(`Found ${itemsToCheck.length} open issues to check.`);

            let processedCount = 0;

            for (const issue of itemsToCheck) {
              const createdAt = new Date(issue.created_at);
              const updatedAt = new Date(issue.updated_at);
              const reactionCount = issue.reactions.total_count;

              // Basic thresholds
              if (reactionCount >= 5) {
                continue;
              }

              // Skip if it has a maintainer label
              if (issue.labels.some(label => label.name.toLowerCase().includes('maintainer'))) {
                continue;
              }

              let isStale = updatedAt < tenDaysAgo;

              // If apparently active, check if it's only bot activity
              if (!isStale) {
                try {
                  const comments = await github.rest.issues.listComments({
                    owner: context.repo.owner,
                    repo: context.repo.repo,
                    issue_number: issue.number,
                    per_page: 100,
                    sort: 'created',
                    direction: 'desc'
                  });

                  const lastHumanComment = comments.data.find(comment => comment.user.type !== 'Bot');
                  if (lastHumanComment) {
                    isStale = new Date(lastHumanComment.created_at) < tenDaysAgo;
                  } else {
                    // No human comments. Check if creator is human.
                    if (issue.user.type !== 'Bot') {
                       isStale = createdAt < tenDaysAgo;
                    } else {
                       isStale = true; // Bot created, only bot comments
                    }
                  }
                } catch (error) {
                  core.warning(`Failed to fetch comments for issue #${issue.number}: ${error.message}`);
                  continue;
                }
              }

              if (isStale) {
                processedCount++;
                const message = `Closing stale issue #${issue.number}: "${issue.title}" (${issue.html_url})`;
                core.info(message);

                if (!dryRun) {
                  // Add label
                  await github.rest.issues.addLabels({
                    owner: context.repo.owner,
                    repo: context.repo.repo,
                    issue_number: issue.number,
                    labels: [batchLabel]
                  });

                  // Add comment
                  await github.rest.issues.createComment({
                    owner: context.repo.owner,
                    repo: context.repo.repo,
                    issue_number: issue.number,
                    body: 'Hello! As part of our effort to keep our backlog manageable and focus on the most active issues, we are tidying up older reports.\n\nIt looks like this issue hasn\'t been active for a while, so we are closing it for now. However, if you are still experiencing this bug on the latest stable build, please feel free to comment on this issue or create a new one with updated details.\n\nThank you for your contribution!'
                  });

                  // Close issue
                  await github.rest.issues.update({
                    owner: context.repo.owner,
                    repo: context.repo.repo,
                    issue_number: issue.number,
                    state: 'closed',
                    state_reason: 'not_planned'
                  });
                }
              }
            }

            core.info(`\nTotal issues processed: ${processedCount}`);
