name: Labeler

on:
  issues:
    types: [opened]
  pull_request_target:
    types: [opened, synchronize, reopened]
  discussion:
    types: [created]

jobs:
  label-priority:
    # Author-based priority labels: only on issue/PR/discussion creation, not on PR updates.
    if: github.event_name != 'pull_request_target' || github.event.action == 'opened'
    runs-on: ubuntu-latest
    permissions:
      issues: write
      pull-requests: write
      discussions: write
    steps:
      - name: Label New Issue, PR or Discussion
        uses: actions/github-script@v8
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            let labels = [];
            let username = '';
            let issueOrPrNumber = 0;
            let discussionNodeId = '';

            if (context.eventName === 'issues') {
              username = context.payload.issue.user.login;
              issueOrPrNumber = context.payload.issue.number;
            } else if (context.eventName === 'pull_request_target') {
              username = context.payload.pull_request.user.login;
              issueOrPrNumber = context.payload.pull_request.number;
            } else if (context.eventName === 'discussion') {
              username = context.payload.discussion.user.login;
              discussionNodeId = context.payload.discussion.node_id;
            }

            // Maintainer is an Adafruit member; skip the Adafruit perks for their own
            // issues/PRs and treat them as a plain contributor (Prio only).
            const isOwner = username.toLowerCase() === 'hathach';

            // Check if an Adafruit member: Adafruit + Sponsor + top priority
            if (!isOwner) {
              try {
                const adafruitResponse = await github.rest.orgs.checkMembershipForUser({
                  org: 'adafruit',
                  username: username
                });

                if (adafruitResponse.status === 204) {
                  console.log('Adafruit Member');
                  labels = ['Adafruit 🌸', 'Sponsor 💖', 'Prio Top 🚨'];
                }
              } catch (error) {
                console.log('Not an Adafruit member');
              }
            }

            // Check if a public GitHub Sponsor of the repo owner.
            // Word ($32) tier and up get triage priority; DWORD/QWORD ($128+) go to the top.
            // Private sponsorships are not visible to GITHUB_TOKEN, so only public sponsors are detected.
            if (labels.length === 0) {
              try {
                const result = await github.graphql(`
                  query($sponsorable: String!, $sponsor: String!) {
                    user(login: $sponsorable) {
                      isSponsoredBy(accountLogin: $sponsor)
                      sponsorshipsAsMaintainer(includePrivate: false, first: 100) {
                        nodes {
                          sponsorEntity {
                            ... on User { login }
                            ... on Organization { login }
                          }
                          tier { monthlyPriceInDollars }
                        }
                      }
                    }
                  }`, { sponsorable: context.repo.owner, sponsor: username });

                const owner = result.user;
                if (owner && owner.isSponsoredBy) {
                  let monthly = 0;
                  const nodes = (owner.sponsorshipsAsMaintainer && owner.sponsorshipsAsMaintainer.nodes) || [];
                  for (const node of nodes) {
                    const login = node.sponsorEntity && node.sponsorEntity.login;
                    if (login && login.toLowerCase() === username.toLowerCase()) {
                      monthly = (node.tier && node.tier.monthlyPriceInDollars) || 0;
                      break;
                    }
                  }

                  if (monthly >= 128) {
                    console.log('Sponsor (DWORD/QWORD tier)');
                    labels = ['Sponsor 💖', 'Prio Top 🚨'];
                  } else if (monthly >= 32) {
                    console.log('Sponsor (Word tier)');
                    labels = ['Sponsor 💖', 'Prio 📌'];
                  } else {
                    console.log('Sponsor (below Word tier or tier not visible)');
                    labels = ['Sponsor 💖'];
                  }
                } else {
                  console.log('Not a public sponsor');
                }
              } catch (error) {
                console.log('Sponsor lookup failed: ' + error.message);
              }
            }

            // Check if a contributor: prioritized in triage queue
            if (labels.length === 0) {
              try {
                const collaboratorResponse = await github.rest.repos.checkCollaborator({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  username: username
                });

                if (collaboratorResponse.status === 204) {
                  console.log('Contributor');
                  labels = ['Prio 📌'];
                }
              } catch (error) {
                console.log('Not a contributor');
              }
            }

            if (labels.length !== 0) {
              if (context.eventName === 'discussion') {
                // Discussions are not covered by the REST issues API; resolve the label
                // names to node IDs and attach them with the GraphQL labelable mutation.
                const labelIds = [];
                for (const name of labels) {
                  const res = await github.graphql(`
                    query($owner: String!, $repo: String!, $name: String!) {
                      repository(owner: $owner, name: $repo) {
                        label(name: $name) { id }
                      }
                    }`, { owner: context.repo.owner, repo: context.repo.repo, name: name });
                  if (res.repository.label) {
                    labelIds.push(res.repository.label.id);
                  }
                }
                if (labelIds.length !== 0) {
                  await github.graphql(`
                    mutation($labelableId: ID!, $labelIds: [ID!]!) {
                      addLabelsToLabelable(input: { labelableId: $labelableId, labelIds: $labelIds }) {
                        clientMutationId
                      }
                    }`, { labelableId: discussionNodeId, labelIds: labelIds });
                }
              } else {
                await github.rest.issues.addLabels({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  issue_number: issueOrPrNumber,
                  labels: labels
                });
              }
            }

  # Path-based Port labels: attach "Port <ip>" when a PR touches the matching
  # dcd/hcd driver under src/portable/. Mapping lives in .github/labeler.yml.
  label-port:
    if: github.event_name == 'pull_request_target'
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
      issues: write # allow auto-creating a Port label that doesn't exist yet
    steps:
      - uses: actions/labeler@v5
        with:
          configuration-path: .github/labeler.yml
          # sync-labels so a Port label is removed once a PR no longer touches
          # that driver (job reruns on synchronize). Only labels listed in
          # labeler.yml are managed, so author-based Prio/Sponsor labels are untouched.
          sync-labels: true
