import { zipArrays } from "@/lib/zip";
import { FC, PropsWithChildren, useMemo } from "react";

export const TCMD: FC<{ body: string }> = ({ body }) => {
  const elements = useMemo(() => createElements(body), [body]);
  return (
    <>
      <pre>{JSON.stringify(elements,null,2)}</pre>
    </>
  );
};

const createElements = (body: string) => {
  const tokens = tokenize(body);

  return tokens;
};

type InlineToken = {
  type: "text" | "bold";
  content: string;
};

type Line = string | InlineToken[];

type MultilineToken = {
  type: "code";
  lines: Token[];
};

type Token = {
  type: "h1" | "h2" | "h3" | "p";
  line: Line;
};

const tokenize = (md: string) => {
  const tokens: (Token | MultilineToken)[] = [];
  md = md.replace(/(?<=[a-z])\n(?=[a-z])/g, " ");
  const lines = md.split("\n");
  const multilineFlags = {
    heading: 0,
  };

  const tokenMatches = [
    {
      rx: /^\s*#\s/,
      create: (line: Line) => tokens.push({ type: "h1", line }),
    },
    {
      rx: /^\s*##\s/,
      create: (line: Line) => tokens.push({ type: "h2", line }),
    },
    {
      rx: /^\s*###\s/,
      create: (line: Line) => tokens.push({ type: "h3", line }),
    },
  ];

  for (let line of lines) {
    let foundLine = false;
    token:
    for (const token of tokenMatches) {
      if (!token.rx.test(line)) continue token;
      foundLine = true;
      line = line.replace(token.rx, "").trim();

      const lineContent = tokenizeInline(line);
      token.create(lineContent);
    }

    if (foundLine) continue;

    tokens.push({
      type: "p",
      line: tokenizeInline(line),
    });
  }

  console.log(tokens);
  return tokens.filter((t) => (t as Token).line || (t as MultilineToken).lines);
};

const tokenizeInline = (line: string) => {
  line = line.trim();
  const originalLine = line;
  const insertMarker = "{^}";
  const tokens: InlineToken[] = [];

  const tokenMatches = [
    {
      rx: /\*\*(.*?)\*\*/g,
      create: (content: string) =>
        tokens.push({
          content,
          type: "bold",
        }),
    },
  ];
  for (const token of tokenMatches) {
    let match;
    let last = 0;
    while ((match = token.rx.exec(line)) !== null) {
      const tokenStart = match.index;
      const tokenEnd = match.index + match[0].length;
      console.log(tokenEnd, token.rx.lastIndex);
      token.create(line.substring(tokenStart, tokenEnd));
      line = line.slice(last, tokenStart) + "{^}" +
        line.slice(tokenEnd, line.length);
      last = tokenEnd;
    }
  }

  if (tokens.length) {
    return zipArrays(
      line.split(insertMarker).map((t): InlineToken => ({
        content: t,
        type: "text",
      })),
      tokens,
    ).filter((t) => t.content);
  }
  return originalLine;
};
