name: Auto Response

on:
  issues:
    types: [opened, reopened, labeled, unlabeled]
  pull_request_target:
    types: [opened, labeled, unlabeled]

permissions: {}

jobs:
  contributor-tier-issues:
    if: >-
      (github.event_name == 'issues' &&
      (github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'labeled' || github.event.action == 'unlabeled')) ||
      (github.event_name == 'pull_request_target' &&
      (github.event.action == 'labeled' || github.event.action == 'unlabeled'))
    runs-on: blacksmith-2vcpu-ubuntu-2404
    permissions:
      issues: write
    steps:
      - name: Apply contributor tier label for issue author
        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
        with:
          script: |
            const owner = context.repo.owner;
            const repo = context.repo.repo;
            const issue = context.payload.issue;
            const pullRequest = context.payload.pull_request;
            const target = issue ?? pullRequest;
            const contributorTierRules = [
              { label: "distinguished contributor", minMergedPRs: 50 },
              { label: "principal contributor", minMergedPRs: 20 },
              { label: "experienced contributor", minMergedPRs: 10 },
              { label: "trusted contributor", minMergedPRs: 5 },
            ];
            const contributorTierLabels = contributorTierRules.map((rule) => rule.label);
            const contributorTierColor = "2ED9FF"; // Keep in sync with .github/workflows/labeler.yml
            const managedContributorLabels = new Set(contributorTierLabels);
            const action = context.payload.action;
            const changedLabel = context.payload.label?.name;

            if (!target) return;
            if ((action === "labeled" || action === "unlabeled") && !managedContributorLabels.has(changedLabel)) {
              return;
            }

            const author = target.user;
            if (!author || author.type === "Bot") return;

            function contributorTierDescription(rule) {
              return `Contributor with ${rule.minMergedPRs}+ merged PRs.`;
            }

            async function ensureContributorTierLabels() {
              for (const rule of contributorTierRules) {
                const label = rule.label;
                const expectedDescription = contributorTierDescription(rule);
                try {
                  const { data: existing } = await github.rest.issues.getLabel({ owner, repo, name: label });
                  const currentColor = (existing.color || "").toUpperCase();
                  const currentDescription = (existing.description || "").trim();
                  if (currentColor !== contributorTierColor || currentDescription !== expectedDescription) {
                    await github.rest.issues.updateLabel({
                      owner,
                      repo,
                      name: label,
                      new_name: label,
                      color: contributorTierColor,
                      description: expectedDescription,
                    });
                  }
                } catch (error) {
                  if (error.status !== 404) throw error;
                  await github.rest.issues.createLabel({
                    owner,
                    repo,
                    name: label,
                    color: contributorTierColor,
                    description: expectedDescription,
                  });
                }
              }
            }

            function selectContributorTier(mergedCount) {
              const matchedTier = contributorTierRules.find((rule) => mergedCount >= rule.minMergedPRs);
              return matchedTier ? matchedTier.label : null;
            }

            let contributorTierLabel = null;
            try {
              const { data: mergedSearch } = await github.rest.search.issuesAndPullRequests({
                q: `repo:${owner}/${repo} is:pr is:merged author:${author.login}`,
                per_page: 1,
              });
              const mergedCount = mergedSearch.total_count || 0;
              contributorTierLabel = selectContributorTier(mergedCount);
            } catch (error) {
              core.warning(`failed to evaluate contributor tier status: ${error.message}`);
              return;
            }

            await ensureContributorTierLabels();

            const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
              owner,
              repo,
              issue_number: target.number,
            });
            const keepLabels = currentLabels
              .map((label) => label.name)
              .filter((label) => !contributorTierLabels.includes(label));

            if (contributorTierLabel) {
              keepLabels.push(contributorTierLabel);
            }

            await github.rest.issues.setLabels({
              owner,
              repo,
              issue_number: target.number,
              labels: [...new Set(keepLabels)],
            });

  first-interaction:
    if: github.event.action == 'opened'
    runs-on: blacksmith-2vcpu-ubuntu-2404
    permissions:
      issues: write
      pull-requests: write
    steps:
      - name: Greet first-time contributors
        uses: actions/first-interaction@2ec0f0fd78838633cd1c1342e4536d49ef72be54 # v1
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          issue-message: |
            Thanks for opening this issue.

            Before maintainers triage it, please confirm:
            - Repro steps are complete and run on latest `main`
            - Environment details are included (OS, Rust version, ZeroClaw version)
            - Sensitive values are redacted

            This helps us keep issue throughput high and response latency low.
          pr-message: |
            Thanks for contributing to ZeroClaw.

            For faster review, please ensure:
            - PR template sections are fully completed
            - `cargo fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` are included
            - If automation/agents were used heavily, add brief workflow notes
            - Scope is focused (prefer one concern per PR)

            See `CONTRIBUTING.md` and `docs/pr-workflow.md` for full collaboration rules.

  labeled-routes:
    if: github.event.action == 'labeled'
    runs-on: blacksmith-2vcpu-ubuntu-2404
    permissions:
      issues: write
      pull-requests: write
    steps:
      - name: Handle label-driven responses
        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
        with:
          script: |
            const label = context.payload.label?.name;
            if (!label) return;

            const issue = context.payload.issue;
            const pullRequest = context.payload.pull_request;
            const target = issue ?? pullRequest;
            if (!target) return;

            const isIssue = Boolean(issue);
            const issueNumber = target.number;
            const owner = context.repo.owner;
            const repo = context.repo.repo;

            const rules = [
              {
                label: "r:support",
                close: true,
                closeIssuesOnly: true,
                closeReason: "not_planned",
                message:
                  "This looks like a usage/support request. Please use README + docs first, then open a focused bug with repro details if behavior is incorrect.",
              },
              {
                label: "r:needs-repro",
                close: false,
                message:
                  "Thanks for the report. Please add deterministic repro steps, exact environment, and redacted logs so maintainers can triage quickly.",
              },
              {
                label: "invalid",
                close: true,
                closeIssuesOnly: true,
                closeReason: "not_planned",
                message:
                  "Closing as invalid based on current information. If this is still relevant, open a new issue with updated evidence and reproducible steps.",
              },
              {
                label: "duplicate",
                close: true,
                closeIssuesOnly: true,
                closeReason: "not_planned",
                message:
                  "Closing as duplicate. Please continue discussion in the canonical linked issue/PR.",
              },
            ];

            const rule = rules.find((entry) => entry.label === label);
            if (!rule) return;

            const marker = `<!-- auto-response:${rule.label} -->`;
            const comments = await github.paginate(github.rest.issues.listComments, {
              owner,
              repo,
              issue_number: issueNumber,
              per_page: 100,
            });

            const alreadyCommented = comments.some((comment) =>
              (comment.body || "").includes(marker)
            );

            if (!alreadyCommented) {
              await github.rest.issues.createComment({
                owner,
                repo,
                issue_number: issueNumber,
                body: `${rule.message}\n\n${marker}`,
              });
            }

            if (!rule.close) return;
            if (rule.closeIssuesOnly && !isIssue) return;
            if (target.state === "closed") return;

            if (isIssue) {
              await github.rest.issues.update({
                owner,
                repo,
                issue_number: issueNumber,
                state: "closed",
                state_reason: rule.closeReason || "not_planned",
              });
            } else {
              await github.rest.issues.update({
                owner,
                repo,
                issue_number: issueNumber,
                state: "closed",
              });
            }
