/**
 * engine/comment-classifier.js — P-f23classifier (F2 + F3)
 *
 * Host-agnostic PR-comment body classifiers shared by engine/github.js and
 * engine/ado.js pollers. Three pure body-only predicates:
 *
 *   isPreviewStatusBody(body) — Firebase / Appetize / Deploy / Preview bot
 *     signatures + Coverage/Build/Test/Deploy/Pipeline report headings +
 *     shields.io-style badge images. Ported from engine/github.js
 *     `_isPreviewStatusComment` body checks. ADO has no `user.type === 'bot'`
 *     equivalent, so the GH-side bot-author gate stays in github.js — this
 *     module's body match is what both pollers consume.
 *
 *   hasMinionsMarker(body) — structural `<!-- minions:agent=… kind=… -->`
 *     check using gh-comment.MINIONS_COMMENT_MARKER_RE. Strict: marker must
 *     occupy the body's first line entirely (no leading content, no trailing
 *     content on the same line). Same semantics as the GH-side
 *     `_isMinionsAuthoredComment` body check.
 *
 *   hasVerdictPrefix(body) — `VERDICT: APPROVE | REQUEST_CHANGES` prefix
 *     check. Tightened in P-f4verdictregex (F4, Wave 3): requires a line
 *     that starts (under /m) with optional whitespace, an optional bold
 *     (`**` / `__`) or heading (`#+ `) marker, the literal `VERDICT:` token,
 *     whitespace, and `APPROVE` or `REQUEST_CHANGES` ending on a word
 *     boundary. Case-sensitive; legacy lowercase / `REQUEST-CHANGES` /
 *     `REQUEST CHANGES` variants no longer match. Strict body-position-0 is
 *     NOT required — real verdict bodies have preambles ~1/3 of the time,
 *     so any line-start position counts. Quoted (`> VERDICT:`) and inline
 *     mid-paragraph mentions are rejected (line-start anchor + only `**`,
 *     `__`, `#+` allowed before `VERDICT:`).
 *
 * IMPORTANT — author identity is intentionally NOT consulted here. These are
 * body-only predicates. Callers MUST combine them with their own identity
 * gates before treating a comment as agent-authored:
 *
 *   GitHub: `comment.viewerDidAuthor === true`, backfilled via `gh api user`
 *           by engine/github.js `_backfillViewerDidAuthor`. The combined
 *           gate (`viewerDidAuthor && hasMinionsMarker`) is what makes the
 *           marker non-spoofable on GH.
 *
 *   ADO:    `comment.author.uniqueName` (or displayName / id / descriptor)
 *           matched case-insensitively against
 *           `config.engine.minionsAdoIdentities`. ADO has no
 *           `viewerDidAuthor` equivalent, so a human pasting our marker
 *           would otherwise be misclassified as agent-authored. The combined
 *           gate (`isMinionsAdoAuthor && hasMinionsMarker`) is the
 *           structural complement that prevents marker spoofing.
 *
 * Marker-presence ALONE never classifies a comment as agent on either
 * platform — that contract is enforced at the caller, not here.
 */

const { MINIONS_COMMENT_MARKER_RE } = require('./gh-comment');

// ── Preview / status / CI-report body patterns ──────────────────────────────
// Coverage / Build / Test / Deploy / Pipeline report headings (level-1-to-3).
const _CI_REPORT_HEADING_RE =
  /^#{1,3}\s*(Coverage|Build|Test|Deploy|Pipeline)\s*(Report|Status|Result|Summary)/i;

// shields.io / similar badge images.
const _BADGE_RE = /!\[.*\]\(https?:\/\/.*badge/i;

// Firebase App Distribution / Appetize / Preview / Deploy headings.
const _PREVIEW_HEADING_RE =
  /^#{1,3}\s*(Firebase(?:\s+App\s+Distribution)?|Appetize|Preview|Deploy(?:ment)?|Status)\b/i;

const _FIREBASE_BRAND_RE = /\bFirebase\s+App\s+Distribution\b/i;
const _FIREBASE_URL_RE = /\bappdistribution\.firebase\b/i;
const _APPETIZE_URL_RE = /\bappetize\.io\b/i;

// "deploy ready", "deployment available", "preview succeeded", etc.
const _DEPLOY_READY_RE =
  /\b(?:deploy|deployment|preview)\s+(?:ready|available|succeeded|complete|completed)\b/i;

function isPreviewStatusBody(body) {
  const text = String(body || '');
  if (!text) return false;
  if (_CI_REPORT_HEADING_RE.test(text)) return true;
  if (_BADGE_RE.test(text)) return true;
  if (_PREVIEW_HEADING_RE.test(text)) return true;
  if (_FIREBASE_BRAND_RE.test(text)) return true;
  if (_FIREBASE_URL_RE.test(text)) return true;
  if (_APPETIZE_URL_RE.test(text)) return true;
  if (_DEPLOY_READY_RE.test(text)) return true;
  return false;
}

// ── Structural Minions marker ──────────────────────────────────────────────
//
// MINIONS_COMMENT_MARKER_RE uses the /m flag so its `^` anchor matches the
// start of ANY line. For body classification we additionally require the
// marker to occupy the FIRST line of the body entirely — no leading text, no
// trailing content on the same line. That matches the body-only contract
// gh-comment.buildMinionsCommentBody produces (marker, \n\n, body) and
// prevents quoted/blockquoted markers in human replies from triggering the
// classifier.
//
// P-bfa-s1-bom-marker (settlement): strip an optional leading BOM (\uFEFF)
// followed by any ASCII/Unicode whitespace before applying the regex.
// Copy-paste flows from Word, VSCode-with-BOM, and editors that auto-insert
// leading spaces would otherwise be misclassified as un-marked. The
// blockquote rejection (lines beginning with `> <!--`) is preserved — `>`
// is not whitespace and is not stripped, so quoted markers remain rejected.
function hasMinionsMarker(body) {
  const text = String(body || '').replace(/^\uFEFF?\s*/, '');
  if (!text) return false;
  const m = MINIONS_COMMENT_MARKER_RE.exec(text);
  if (!m) return false;
  if (m.index !== 0) return false;
  const lineEnd = text.indexOf('\n');
  const firstLine = lineEnd === -1 ? text : text.slice(0, lineEnd);
  return firstLine.trim() === m[0].trim();
}

// ── VERDICT prefix ─────────────────────────────────────────────────────────
//
// P-f4verdictregex (F4, Wave 3): tightened from the GH-flavored permissive
// regex to a strict line-start form. The body must contain a line that
// starts with optional whitespace, an optional bold (`**` / `__`) or
// heading (`#+ `) marker, the literal `VERDICT:` token, whitespace, and
// `APPROVE` or `REQUEST_CHANGES` ending on a word boundary. Case-sensitive
// (no /i flag) — playbooks/review.md emits the canonical uppercase form.
// /m flag lets a verdict appear after a preamble (~1/3 of real bodies have
// a preamble before the verdict line). Quoted (`> VERDICT:`) and inline
// mid-paragraph mentions are rejected because nothing other than
// whitespace + `**` / `__` / `#+ ` is allowed before `VERDICT:`.
//
// The optional trailing `(?:\*\*|__)?` group lets `__bold__` markdown close
// cleanly — `_` is a word character, so without consuming the closing
// `__` the trailing `\b` would not match `__VERDICT: APPROVE__`. The
// alternation backtracks for `**...**` bodies (trailing `**` consumed then
// `\b` fails, engine retries with 0-width trailing match and `\b` succeeds
// at the `E` → `*` transition).
const _VERDICT_PREFIX_RE =
  /^\s*(?:\*\*|__|#+\s*)?VERDICT:\s+(APPROVE|REQUEST_CHANGES)(?:\*\*|__)?\b/m;

function hasVerdictPrefix(body) {
  return _VERDICT_PREFIX_RE.test(String(body || ''));
}

module.exports = {
  isPreviewStatusBody,
  hasMinionsMarker,
  hasVerdictPrefix,
};
