/**
 * Text helpers — port of Rank Math's researches/{wordCount,fleschReading,…}.js
 * but tuned for Vietnamese as the primary content language.
 */

const VIETNAMESE_VOWELS_RE = /[aeiouyàáạảãâầấậẩẫăằắặẳẵèéẹẻẽêềếệểễìíịỉĩòóọỏõôồốộổỗơờớợởỡùúụủũưừứựửữỳýỵỷỹ]/i;

export function stripMarkdown(md: string): string {
  return md
    // code blocks
    .replace(/```[\s\S]*?```/g, " ")
    .replace(/`[^`]*`/g, " ")
    // images
    .replace(/!\[[^\]]*\]\([^)]*\)/g, " ")
    // links — keep label, drop URL
    .replace(/\[([^\]]+)\]\([^)]*\)/g, "$1")
    // headings, blockquotes, list markers, hr
    .replace(/^#{1,6}\s+/gm, "")
    .replace(/^>\s?/gm, "")
    .replace(/^[*+-]\s+/gm, "")
    .replace(/^\d+\.\s+/gm, "")
    .replace(/^---+\s*$/gm, " ")
    // emphasis
    .replace(/(\*\*|__)(.*?)\1/g, "$2")
    .replace(/(\*|_)(.*?)\1/g, "$2")
    // raw HTML tags
    .replace(/<[^>]+>/g, " ")
    // collapse whitespace
    .replace(/\s+/g, " ")
    .trim();
}

export function wordCount(plainText: string): number {
  if (!plainText) return 0;
  return plainText.split(/\s+/u).filter(Boolean).length;
}

export function readMinutes(plainText: string, wpm = 220): number {
  return Math.max(1, Math.ceil(wordCount(plainText) / wpm));
}

export function escapeRegex(s: string): string {
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

export function normalizeQuotes(s: string): string {
  return s
    .replace(/[\u2018\u2019\u201A\u201B]/g, "'")
    .replace(/[\u201C\u201D\u201E\u201F]/g, '"');
}

/**
 * Approximate Flesch Reading Ease.
 * Original (English): 206.835 - 1.015·(words/sentences) - 84.6·(syllables/words)
 * For Vietnamese (mostly monosyllabic), we approximate syllable count == word count
 * which biases the score upward — that's fine since we treat 60+ as "easy enough".
 */
export function fleschReading(plainText: string, locale: "en" | "vi" = "vi"): number | null {
  const text = plainText.trim();
  if (!text) return null;
  const sentences = (text.match(/[.!?…]+/g) ?? []).length || 1;
  const words = wordCount(text);
  if (words < 30) return null;

  let syllables = 0;
  if (locale === "vi") {
    // Vietnamese: each whitespace-separated token is roughly one syllable.
    syllables = words;
  } else {
    syllables = text
      .toLowerCase()
      .split(/\s+/)
      .reduce((acc, w) => acc + Math.max(1, (w.match(VIETNAMESE_VOWELS_RE) ?? []).length), 0);
  }

  const score = 206.835 - 1.015 * (words / sentences) - 84.6 * (syllables / words);
  return Math.max(0, Math.min(100, +score.toFixed(1)));
}

export function extractSubheadings(md: string): string[] {
  const out: string[] = [];

  // Markdown headings (## Heading)
  const lines = md.split("\n");
  let inFence = false;
  for (const line of lines) {
    if (/^```/.test(line)) {
      inFence = !inFence;
      continue;
    }
    if (inFence) continue;
    const m = line.match(/^(#{2,6})\s+(.+?)\s*$/);
    if (m) out.push(m[2].replace(/[#*_`]/g, "").trim());
  }

  // HTML headings (<h2>…</h2>) — covers WP-imported content
  const htmlRe = /<h([2-6])(?:\s[^>]*)?>([\s\S]*?)<\/h\1>/gi;
  let m: RegExpExecArray | null;
  while ((m = htmlRe.exec(md)) !== null) {
    const text = m[2].replace(/<[^>]+>/g, "").trim();
    if (text) out.push(text);
  }

  return out;
}

interface LinkInfo {
  internal: string[];
  external: string[];
  images: Array<{ src: string; alt: string }>;
}

export function extractLinks(md: string, host: string): LinkInfo {
  const internal: string[] = [];
  const external: string[] = [];
  const images: Array<{ src: string; alt: string }> = [];

  const imgRe = /!\[([^\]]*)\]\(([^) ]+)(?:\s+"[^"]*")?\)/g;
  let m: RegExpExecArray | null;
  while ((m = imgRe.exec(md)) !== null) {
    images.push({ alt: m[1] ?? "", src: m[2] });
  }

  const linkRe = /(?<!\!)\[([^\]]+)\]\(([^) ]+)(?:\s+"[^"]*")?\)/g;
  while ((m = linkRe.exec(md)) !== null) {
    const url = m[2];
    if (!url) continue;
    if (url.startsWith("/") || url.startsWith("#")) {
      internal.push(url);
    } else if (/^https?:\/\//i.test(url)) {
      try {
        const u = new URL(url);
        if (host && u.host === host) internal.push(url);
        else external.push(url);
      } catch {
        external.push(url);
      }
    }
  }

  // Also pick up raw <a> tags + <img>
  const aRe = /<a\s[^>]*href=["']([^"']+)["'][^>]*>/gi;
  while ((m = aRe.exec(md)) !== null) {
    const url = m[1];
    if (url.startsWith("/")) internal.push(url);
    else if (/^https?:\/\//i.test(url)) {
      try {
        const u = new URL(url);
        (u.host === host ? internal : external).push(url);
      } catch {
        external.push(url);
      }
    }
  }
  const imgTagRe = /<img\s[^>]*src=["']([^"']+)["'][^>]*?(?:alt=["']([^"']*)["'])?[^>]*>/gi;
  while ((m = imgTagRe.exec(md)) !== null) {
    images.push({ src: m[1], alt: m[2] ?? "" });
  }

  return { internal, external, images };
}

export function countMatches(text: string, needle: string): number {
  if (!needle) return 0;
  const re = new RegExp(escapeRegex(needle), "gi");
  return (text.match(re) ?? []).length;
}

/**
 * Generate keyword combinations like Rank Math's `combinations.js`.
 * "Bitcoin giá hôm nay" → ["bitcoin giá hôm nay","bitcoin giá hôm","giá hôm nay",…]
 */
export function keywordCombinations(keyword: string): string[] {
  const parts = keyword.toLowerCase().trim().split(/\s+/).filter(Boolean);
  if (parts.length === 0) return [];
  const combos = new Set<string>([parts.join(" ")]);
  for (let len = parts.length - 1; len >= 1; len--) {
    for (let start = 0; start + len <= parts.length; start++) {
      combos.add(parts.slice(start, start + len).join(" "));
    }
  }
  return Array.from(combos);
}
