import { fromMarkdown } from "mdast-util-from-markdown";
import { gfmFromMarkdown } from "mdast-util-gfm";
import { gfmTableFromMarkdown } from "mdast-util-gfm-table";
import { unified } from "unified";
import { VFile } from "vfile";
import rehypeRaw from "rehype-raw";
import remarkGfm from "remark-gfm";
import remarkMath from "remark-math";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import { RootContent } from "./libs/types";

export function createAstByText(content: string) {
  const ast = fromMarkdown(content, {
    mdastExtensions: [gfmTableFromMarkdown(), gfmFromMarkdown()],
  });
  return ast;
}

export function createAstUsingUnified(content: string) {
  const file = new VFile();
  file.value = content;

  const processor = unified()
    .use(remarkParse)
    .use([remarkGfm, remarkMath])
    .use(remarkRehype)
    .use([rehypeRaw]);

  const ast = processor.parse(file);
  return ast;
}

export function getPlainTextByAstNodes(nodes: RootContent[]) {
  let string = "";
  nodes.forEach(child => {
    if (child.type === "text") {
      string += child.value;
    } else if (child.type === "link" || child.type === "strong" || child.type === "emphasis") {
      string += getPlainTextByAstNodes(child.children);
    }
  });
  return string;
}

function formatPlainTexts(texts: string[]) {
  const formatedText: string[] = [];
  texts.forEach(text => {
    const trimedText = text.trim();
    if (!trimedText) {
      return;
    }
    const ts = trimedText.split("\n");
    formatedText.push(...ts);
  });

  return formatedText;
}

function getPlainTextsByAstNodes(nodes: RootContent[]) {
  const texts: string[] = [];
  nodes.forEach(child => {
    if (child.type === "heading" || child.type === "paragraph") {
      texts.push(getPlainTextByAstNodes(child.children));
    } else if (child.type === "list" || child.type === "listItem") {
      texts.push(...getPlainTextsByAstNodes(child.children));
    }
  });
  return formatPlainTexts(texts);
}

export function getPlainTextsByMarkdown(content: string): string[] {
  const ast = createAstUsingUnified(content);

  return getPlainTextsByAstNodes(ast.children);
}
