/**
 * Guards for text that reaches the poster surface.
 *
 * Story sections are written for the caption model, so they carry narrative
 * scaffolding ("Problem introduction: ...", "Why it persists: ...") and, when a
 * website scrape returns a tagline instead of a service, marketing slogans.
 * Rendered verbatim on an image those read as machine output — the scaffolding
 * label becomes a feature heading, and a slogan used as a service produces
 * nonsense like "With smarter. faster. more intelligent.:".
 */

/**
 * Narrative role prefixes added by the creative brief builder. Each ends the
 * scaffolding clause, so everything up to and including it is dropped.
 */
const SCAFFOLD_PREFIXES: RegExp[] = [
  /^problem introduction\s*:\s*/i,
  /^why it persists\s*:\s*/i,
  /^the useful reframe\s*:\s*/i,
  /^how it works in practice\s*:\s*/i,
  /^framework role\s*:\s*/i,
  /^maps to\s*:\s*/i,
  /^for .{1,80}?,\s*a realistic situation is dealing with\s*:\s*/i,
  /^a common attempt is to patch around the issue instead of addressing\s+/i,
];

/** Remove caption-brief scaffolding so only the customer-facing sentence remains. */
export function stripNarrativeScaffolding(text: string | null | undefined): string {
  let out = (text ?? "").trim().replace(/\s+/g, " ");
  if (!out) return "";

  // Applied repeatedly — beats can stack a role prefix onto an already framed line.
  for (let pass = 0; pass < 3; pass += 1) {
    const before = out;
    for (const prefix of SCAFFOLD_PREFIXES) {
      out = out.replace(prefix, "");
    }
    out = out.trim();
    if (out === before) break;
  }

  // Leading connectives left behind once the prefix is gone.
  out = out.replace(/^(?:that|which|is|are|it|this)\s+/i, "").trim();
  return out ? out.charAt(0).toUpperCase() + out.slice(1) : "";
}

/**
 * True when a phrase is a marketing slogan rather than a nameable service.
 * Slogans break any template that frames the value as a noun ("With X:").
 */
export function looksLikeSlogan(text: string | null | undefined): boolean {
  // A single trailing stop is normal for a service label ("Online faxing."), so
  // it is removed before judging — only internal stops signal a multi-beat tagline.
  const t = (text ?? "").trim().replace(/[.,;:!?]+$/, "").trim();
  if (!t) return true;
  if ((t.match(/[.!?]/g) || []).length >= 1) return true;
  if (/revolutioniz|unleash|game.?chang|next level|best ever|world.?class|cutting.?edge/i.test(t)) {
    return true;
  }
  if (/^(smarter|faster|better|bigger|stronger)\b/i.test(t) && t.split(/\s+/).length <= 6) {
    return true;
  }
  return false;
}

/**
 * Normalize a service phrase for inline use in on-image copy. Returns an empty
 * string when the value is a slogan, so callers fall back to neutral wording
 * instead of rendering it.
 */
export function serviceForInlineCopy(text: string | null | undefined): string {
  const t = (text ?? "").trim().replace(/\s+/g, " ");
  if (!t || looksLikeSlogan(t)) return "";
  return t.replace(/[.,;:!?]+$/, "").trim();
}
