name: PR Triage (Models)

on:
  pull_request_target:
    types: [opened, edited]

permissions:
  pull-requests: write
  issues: write
  models: read

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  triage:
    if: ${{ github.repository == 'meshtastic/Meshtastic-Android' && github.event.pull_request.user.type != 'Bot' }}
    runs-on: ubuntu-24.04-arm
    steps:
      # ─────────────────────────────────────────────────────────────────────────
      # Step 1: Check if PR already has automation/type labels (skip if so)
      # ─────────────────────────────────────────────────────────────────────────
      - name: Check existing labels
        uses: actions/github-script@v9
        id: check-labels
        with:
          script: |
            const skipLabels = new Set(['automation', 'release']);
            const typeLabels = new Set(['bugfix', 'enhancement', 'dependencies', 'repo', 'refactor', 'chore', 'ci', 'build', 'testing', 'documentation']);
            const prLabels = context.payload.pull_request.labels.map(l => l.name);

            const shouldSkipAll = prLabels.some(l => skipLabels.has(l));
            const hasTypeLabel = prLabels.some(l => typeLabels.has(l));

            core.setOutput('skip_all', shouldSkipAll ? 'true' : 'false');
            core.setOutput('has_type_label', hasTypeLabel ? 'true' : 'false');

      # ─────────────────────────────────────────────────────────────────────────
      # Step 2: Quality check (spam/AI-slop detection)
      # ─────────────────────────────────────────────────────────────────────────
      - name: Detect spam or low-quality content
        if: steps.check-labels.outputs.skip_all != 'true'
        uses: actions/ai-inference@v2
        id: quality
        continue-on-error: true
        env:
          PR_TITLE: ${{ github.event.pull_request.title }}
          PR_BODY: ${{ github.event.pull_request.body }}
        with:
          max-tokens: 20
          prompt: |
            Is this GitHub pull request spam, AI-generated slop, or low quality?

            Title: ${{ env.PR_TITLE }}
            Body: ${{ env.PR_BODY }}

            Respond with exactly one of: spam, ai-generated, needs-review, ok
          system-prompt: You detect spam and low-quality contributions. Be conservative - only flag obvious spam or AI slop.
          model: openai/gpt-4o-mini

      - name: Apply quality label if needed
        if: steps.check-labels.outputs.skip_all != 'true' && steps.quality.outputs.response != '' && steps.quality.outputs.response != 'ok'
        uses: actions/github-script@v9
        id: quality-label
        env:
          QUALITY_LABEL: ${{ steps.quality.outputs.response }}
        with:
          script: |
            const label = (process.env.QUALITY_LABEL || '').trim().toLowerCase();
            const labelMeta = {
              'spam': { color: 'd73a4a', description: 'Possible spam' },
              'ai-generated': { color: 'fbca04', description: 'Possible AI-generated low-quality content' },
              'needs-review': { color: 'f9d0c4', description: 'Needs human review' },
            };
            const meta = labelMeta[label];
            if (!meta) return;

            // Ensure label exists
            try {
              await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label });
            } catch (e) {
              if (e.status !== 404) throw e;
              await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: meta.color, description: meta.description });
            }

            // Apply label
            await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, labels: [label] });

            core.setOutput('is_spam', 'true');

      # ─────────────────────────────────────────────────────────────────────────
      # Step 3: Auto-label PR type (bugfix/enhancement/refactor)
      # ─────────────────────────────────────────────────────────────────────────
      - name: Classify PR for labeling
        if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && (steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == '')
        uses: actions/ai-inference@v2
        id: classify
        continue-on-error: true
        env:
          PR_TITLE: ${{ github.event.pull_request.title }}
          PR_BODY: ${{ github.event.pull_request.body }}
        with:
          max-tokens: 30
          prompt: |
            Classify this pull request for the Meshtastic Android app into exactly one category.

            Return exactly one of: bugfix, enhancement, refactor, chore, ci, build, testing, documentation

            Label definitions:
            - bugfix: Fixes a bug, crash, or incorrect behavior
            - enhancement: Adds a new feature, improves UX, adds new functionality, or improves performance
            - refactor: Restructures code without changing behavior, cleans up code, or improves architecture
            - chore: Routine maintenance (dependency updates, config tweaks, version bumps) that doesn't change app behavior
            - ci: Changes to CI/CD workflows, GitHub Actions, or automation scripts
            - build: Changes to build system, Gradle config, build-logic, or compilation settings
            - testing: Adds or modifies tests without changing production code
            - documentation: Documentation-only changes (README, CHANGELOG, code comments, KDoc)

            Title: ${{ env.PR_TITLE }}
            Body: ${{ env.PR_BODY }}
          system-prompt: >
            You classify pull requests into categories for changelog generation.
            Pick the single most specific label. Prefer ci/build/chore/testing/documentation
            over refactor when the change clearly fits those narrower categories.
            Only use bugfix for actual bug fixes, not for CI fixes or build fixes.
            Only use enhancement for user-facing features, not for internal improvements.
          model: openai/gpt-4o-mini

      - name: Apply type label
        if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && steps.classify.outputs.response != ''
        uses: actions/github-script@v9
        env:
          TYPE_LABEL: ${{ steps.classify.outputs.response }}
        with:
          script: |
            const label = (process.env.TYPE_LABEL || '').trim().toLowerCase();
            const labelMeta = {
              'bugfix':        { color: 'd73a4a', description: 'Bug fix' },
              'enhancement':   { color: 'a2eeef', description: 'New feature or enhancement' },
              'refactor':      { color: 'c5def5', description: 'Code restructuring without behavior change' },
              'chore':         { color: 'ededed', description: 'Routine maintenance' },
              'ci':            { color: 'bfd4f2', description: 'CI/CD and automation changes' },
              'build':         { color: 'bfd4f2', description: 'Build system changes' },
              'testing':       { color: 'f9d0c4', description: 'Test additions or modifications' },
              'documentation': { color: '0075ca', description: 'Documentation changes' },
            };
            const meta = labelMeta[label];
            if (!meta) return;

            // Ensure label exists
            try {
              await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label });
            } catch (e) {
              if (e.status !== 404) throw e;
              await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: meta.color, description: meta.description });
            }

            // Apply label
            await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, labels: [label] });
