name: PR Compliance

on:
  pull_request_target:
    branches: [main]
    types: [opened, edited, synchronize]

permissions:
  contents: read
  pull-requests: write

jobs:
  check-pr:
    name: Validate PR
    # Filter on the PR author, not github.actor: actor becomes a maintainer on
    # synchronize/edited events triggered by pushes or merges into a bot branch,
    # which lets bot PRs slip past an actor-based check.
    if: >-
      github.event.pull_request.user.login != 'dependabot[bot]'
      && github.event.pull_request.user.login != 'renovate[bot]'
      && github.event.pull_request.user.login != 'emdashbot[bot]'
      && github.event.pull_request.user.login != 'ask-bonk[bot]'
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Check PR template
        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
        with:
          script: |
            const body = context.payload.pull_request.body || '';
            const pr = context.payload.pull_request;

            // Maintainers (repo owners, org members, and collaborators) are trusted
            // to land features without a pre-approved Discussion link.
            const association = pr.author_association || '';
            const isMaintainer = ['OWNER', 'MEMBER', 'COLLABORATOR'].includes(association);

            const errors = [];

            // Check if the PR body looks like it used the template at all
            const hasTemplate = body.includes('## What does this PR do?') || body.includes('## Type of change');

            if (!hasTemplate) {
              errors.push('This PR does not use the required PR template. Please edit the description to use the [PR template](https://github.com/emdash-cms/emdash/blob/main/.github/PULL_REQUEST_TEMPLATE.md). Copy it into your PR description and fill out all sections.');
            } else {
              // Must have a description (not just the raw template placeholder)
              const descriptionSection = body.match(/## What does this PR do\?\s*\n([\s\S]*?)(?=\n## )/);
              const description = descriptionSection?.[1]?.replace(/<!--[\s\S]*?-->/g, '').trim() || '';
              if (!description || description === 'Closes #') {
                errors.push('Fill out the "What does this PR do?" section with a description of your change.');
              }

              // Must check at least one type
              const typeChecks = [
                /- \[x\] Bug fix/i,
                /- \[x\] Feature/i,
                /- \[x\] Refactor/i,
                /- \[x\] Translation/i,
                /- \[x\] Documentation/i,
                /- \[x\] Performance/i,
                /- \[x\] Tests/i,
                /- \[x\] Chore/i,
              ];
              const hasType = typeChecks.some(re => re.test(body));
              if (!hasType) {
                errors.push('Check at least one "Type of change" checkbox.');
              }

              // If Feature is checked, require a discussion link.
              // Maintainers are exempt: they can approve their own features.
              const isFeature = /- \[x\] Feature/i.test(body);
              if (isFeature && !isMaintainer) {
                const hasDiscussionLink = /github\.com\/emdash-cms\/emdash\/discussions\/\d+/.test(body);
                if (!hasDiscussionLink) {
                  errors.push('Feature PRs require a link to an approved Discussion (https://github.com/emdash-cms/emdash/discussions/categories/ideas). Open a Discussion first, get approval, then link it in the PR.');
                }
              }

              // Must check the "I have read CONTRIBUTING.md" box. Be lenient about
              // formatting: accept the box whether or not CONTRIBUTING.md is still a
              // markdown link (authors often strip the link or tweak the wording).
              const hasReadContributing = /- \[x\][^\n]*\bI have read\b[^\n]*CONTRIBUTING/i.test(body);
              if (!hasReadContributing) {
                errors.push('Check the "I have read CONTRIBUTING.md" checkbox.');
              }
            }

            if (errors.length > 0) {
              const message = [
                '## PR template validation failed',
                '',
                'Please fix the following issues by editing your PR description:',
                '',
                ...errors.map(e => `- ${e}`),
                '',
                'See [CONTRIBUTING.md](https://github.com/emdash-cms/emdash/blob/main/CONTRIBUTING.md) for the full contribution policy.',
              ].join('\n');

              // Leave a comment so the author sees the errors directly
              // Find and update existing bot comment, or create a new one
              const marker = '<!-- pr-compliance-check -->';
              const commentBody = `${marker}\n${message}`;

              const { data: comments } = await github.rest.issues.listComments({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: pr.number,
              });

              const existing = comments.find(c =>
                c.user?.login === 'github-actions[bot]' &&
                c.body?.includes(marker)
              );

              if (existing) {
                await github.rest.issues.updateComment({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  comment_id: existing.id,
                  body: commentBody,
                });
              } else {
                await github.rest.issues.createComment({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  issue_number: pr.number,
                  body: commentBody,
                });
              }

              core.setFailed(message);
            } else {
              // If passing now, remove any previous failure comment
              const marker = '<!-- pr-compliance-check -->';
              const { data: comments } = await github.rest.issues.listComments({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: pr.number,
              });

              const existing = comments.find(c =>
                c.user?.login === 'github-actions[bot]' &&
                c.body?.includes(marker)
              );

              if (existing) {
                await github.rest.issues.deleteComment({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  comment_id: existing.id,
                });
              }
            }
