# This workflow automatically notifies codeowners when an issue is labeled with component labels.
# It reads the CODEOWNERS file to find the maintainers for the labeled components
# and posts a comment mentioning them to ensure they're aware of the issue.

name: Notify Issue Codeowners

on:
  issues:
    types: [labeled]

permissions:
  issues: write
  contents: read

jobs:
  notify-codeowners:
    name: Run
    if: ${{ startsWith(github.event.label.name, format('component{0} ', ':')) }}
    runs-on: ubuntu-latest
    steps:
      - name: Notify codeowners for component issues
        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
        with:
          script: |
            const owner = context.repo.owner;
            const repo = context.repo.repo;
            const issue_number = context.payload.issue.number;
            const labelName = context.payload.label.name;

            console.log(`Processing issue #${issue_number} with label: ${labelName}`);

            // Hidden marker to identify bot comments from this workflow
            const BOT_COMMENT_MARKER = '<!-- issue-codeowner-notify-bot -->';

            // Extract component name from label
            const componentName = labelName.replace('component: ', '');
            console.log(`Component: ${componentName}`);

            try {
              // Fetch CODEOWNERS file from root
              const { data: codeownersFile } = await github.rest.repos.getContent({
                owner,
                repo,
                path: 'CODEOWNERS'
              });
              const codeownersContent = Buffer.from(codeownersFile.content, 'base64').toString('utf8');

              // Parse CODEOWNERS file to extract component mappings
              const codeownersLines = codeownersContent.split('\n')
                .map(line => line.trim())
                .filter(line => line && !line.startsWith('#'));

              let componentOwners = null;

              for (const line of codeownersLines) {
                const parts = line.split(/\s+/);
                if (parts.length < 2) continue;

                const pattern = parts[0];
                const owners = parts.slice(1);

                // Look for component patterns: esphome/components/{component}/*
                const componentMatch = pattern.match(/^esphome\/components\/([^\/]+)\/\*$/);
                if (componentMatch && componentMatch[1] === componentName) {
                  componentOwners = owners;
                  break;
                }
              }

              if (!componentOwners) {
                console.log(`No codeowners found for component: ${componentName}`);
                return;
              }

              console.log(`Found codeowners for '${componentName}': ${componentOwners.join(', ')}`);

              // Separate users and teams
              const userOwners = [];
              const teamOwners = [];

              for (const owner of componentOwners) {
                const cleanOwner = owner.startsWith('@') ? owner.slice(1) : owner;
                if (cleanOwner.includes('/')) {
                  // Team mention (org/team-name)
                  teamOwners.push(`@${cleanOwner}`);
                } else {
                  // Individual user
                  userOwners.push(`@${cleanOwner}`);
                }
              }

              // Remove issue author from mentions to avoid self-notification
              const issueAuthor = context.payload.issue.user.login;
              const filteredUserOwners = userOwners.filter(mention =>
                mention !== `@${issueAuthor}`
              );

              // Check for previous comments from this workflow to avoid duplicate pings
              const comments = await github.paginate(
                github.rest.issues.listComments,
                {
                  owner,
                  repo,
                  issue_number: issue_number
                }
              );

              const previouslyPingedUsers = new Set();
              const previouslyPingedTeams = new Set();

              // Look for comments from github-actions bot that contain codeowner pings for this component
              const workflowComments = comments.filter(comment =>
                comment.user.type === 'Bot' &&
                comment.body.includes(BOT_COMMENT_MARKER) &&
                comment.body.includes(`component: ${componentName}`)
              );

              // Extract previously mentioned users and teams from workflow comments
              for (const comment of workflowComments) {
                // Match @username patterns (not team mentions)
                const userMentions = comment.body.match(/@([a-zA-Z0-9_.-]+)(?![/])/g) || [];
                userMentions.forEach(mention => {
                  previouslyPingedUsers.add(mention); // Keep @ prefix for easy comparison
                });

                // Match @org/team patterns
                const teamMentions = comment.body.match(/@[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+/g) || [];
                teamMentions.forEach(mention => {
                  previouslyPingedTeams.add(mention);
                });
              }

              console.log(`Found ${previouslyPingedUsers.size} previously pinged users and ${previouslyPingedTeams.size} previously pinged teams for component ${componentName}`);

              // Remove previously pinged users and teams
              const newUserOwners = filteredUserOwners.filter(mention => !previouslyPingedUsers.has(mention));
              const newTeamOwners = teamOwners.filter(mention => !previouslyPingedTeams.has(mention));

              const allMentions = [...newUserOwners, ...newTeamOwners];

              if (allMentions.length === 0) {
                console.log('No new codeowners to notify (all previously pinged or issue author is the only codeowner)');
                return;
              }

              // Create comment body
              const mentionString = allMentions.join(', ');
              const commentBody = `${BOT_COMMENT_MARKER}\n👋 Hey ${mentionString}!\n\nThis issue has been labeled with \`component: ${componentName}\` and you've been identified as a codeowner of this component. Please take a look when you have a chance!\n\nThanks for maintaining this component! 🙏`;

              // Post comment
              await github.rest.issues.createComment({
                owner,
                repo,
                issue_number: issue_number,
                body: commentBody
              });

              console.log(`Successfully notified new codeowners: ${mentionString}`);

            } catch (error) {
              console.log('Failed to process codeowner notifications:', error.message);
              console.error(error);
            }
