import { STATE_MARK } from "./state-mark";

export enum NodeType {
  divider = "divider",
  node = "node",
  comment = "comment",
}

export enum ContentType {
  text = "text",
  icon = "icon",
}

export interface IContent {
  type: ContentType;
  value: string;
}

export interface INode {
  type: NodeType;
  state: string;
  value: string | IContent[];
  children: INode[];
}

export interface IParseOption {
  parseContent: boolean;
}

const getChildren = (template: string = ""): IContent[] => {
  if (!template) {
    return [];
  }

  return template
    .replace(/(\[.*?\])/g, "\n$1\n")
    .split("\n")
    .filter((v) => !!v)
    .map((d) => {
      switch (true) {
        case /^\[(.*)\]$/.test(d):
          return {
            type: "icon",
            value: RegExp.$1,
          } as IContent;
        default:
          return {
            type: "text",
            value: d,
          } as IContent;
      }
    });
};

export const parseData = (text: string, options: IParseOption = { parseContent: false }): INode[] => {
  if (!text) {
    return [];
  }
  const root: INode = {
    type: NodeType.node,
    state: "normal",
    value: "",
    children: [],
  };
  const stack: INode[] = [root];

  text
    .split("\n")
    .filter((line) => line.trim())
    .forEach((line) => {
      const re: any = /^(\t*)([#\-~*]?)(.*)$/.exec(line);
      const indent = (re[1] || "").length;
      const prefix = re[2] || "";
      const item: INode = {
        type: NodeType.node,
        state: "normal",
        value: re[3] || "",
        children: [],
      };

      if (prefix === "-" && /^-{2,}$/.test(item.value as string)) {
        item.type = NodeType.divider;
      } else if (prefix === "#") {
        item.type = NodeType.comment;
      } else {
        item.state = STATE_MARK[prefix];
      }

      if (item.type === "node" && options.parseContent) {
        item.value = getChildren(item.value as string);
      }

      while (indent <= stack.length - 2) {
        stack.pop();
      }

      stack[stack.length - 1].children.push(item);
      stack.push(item);
    });

  return root.children;
};

export default parseData;
