import { fromMarkdown } from "mdast-util-from-markdown";
import { toString } from "mdast-util-to-string";
import type { Heading, List, RootContent } from "mdast";

function isHeading(node: RootContent): node is Heading {
  return node.type === "heading";
}

function isList(node: RootContent): node is List {
  return node.type === "list";
}

/**
 * Parse test case descriptions from the `## Test Cases` section of a Markdown doc.
 * Uses mdast to traverse the AST instead of string matching.
 */
export function parseTestCasesFromDoc(markdown: string): string[] {
  const tree = fromMarkdown(markdown);
  const cases: string[] = [];
  let collecting = false;

  for (const node of tree.children) {
    if (isHeading(node)) {
      if (collecting) break;
      if (node.depth === 2 && toString(node) === "Test Cases") {
        collecting = true;
        continue;
      }
    }
    if (collecting && isList(node)) {
      for (const item of node.children) {
        const text = toString(item).trim();
        if (text) {
          cases.push(text);
        }
      }
    }
  }

  return cases;
}

/**
 * Parse `it("...")` descriptions from a test file using regex.
 * Test files are not Markdown, so regex is appropriate here.
 * Uses separate patterns per quote type so that e.g. an apostrophe
 * inside a double-quoted string does not end the match early.
 */
export function parseItDescriptionsFromTest(content: string): string[] {
  const descriptions: string[] = [];
  const regex = /\bit\(\s*"([^"]+)"/gs;
  let match: RegExpExecArray | null;
  while ((match = regex.exec(content)) !== null) {
    descriptions.push(match[1].replace(/\s+/g, " ").trim());
  }
  // Also match single-quoted and backtick-quoted descriptions
  const singleQuoteRegex = /\bit\(\s*'([^']+)'/gs;
  while ((match = singleQuoteRegex.exec(content)) !== null) {
    descriptions.push(match[1].replace(/\s+/g, " ").trim());
  }
  const backtickRegex = /\bit\(\s*`([^`]+)`/gs;
  while ((match = backtickRegex.exec(content)) !== null) {
    descriptions.push(match[1].replace(/\s+/g, " ").trim());
  }
  return descriptions;
}
