import rangeParser from "parse-numeric-range";
import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter";
import tsx from "react-syntax-highlighter/dist/cjs/languages/prism/tsx";
import typescript from "react-syntax-highlighter/dist/cjs/languages/prism/typescript";
import scss from "react-syntax-highlighter/dist/cjs/languages/prism/scss";
import bash from "react-syntax-highlighter/dist/cjs/languages/prism/bash";
import markdown from "react-syntax-highlighter/dist/cjs/languages/prism/markdown";
import json from "react-syntax-highlighter/dist/cjs/languages/prism/json";
import { coldarkDark as defaulttheme } from "react-syntax-highlighter/dist/cjs/styles/prism";
import { BiCopy } from "react-icons/bi";
import { Components } from "react-markdown";
import { generateSlug } from "../utils/general";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import remarkTypograf from "@mavrin/remark-typograf";
import smartypants from "remark-smartypants";
import oembed from "@agentofuser/remark-oembed";
import rehypeRaw from "rehype-raw";
import emoji from "remark-emoji";
import rehypeSanitize from "rehype-sanitize";

SyntaxHighlighter.registerLanguage("tsx", tsx);
SyntaxHighlighter.registerLanguage("typescript", typescript);
SyntaxHighlighter.registerLanguage("scss", scss);
SyntaxHighlighter.registerLanguage("bash", bash);
SyntaxHighlighter.registerLanguage("markdown", markdown);
SyntaxHighlighter.registerLanguage("json", json);

export const StyledMarkdown = ({ html }: { html: string }) => {
  const MarkdownComponents: Components = {
    h1: (props: any) => {
      const arr = props.children;
      let heading = "";

      for (let i = 0; i < arr.length; i++) {
        if (arr[i]?.type !== undefined) {
          for (let j = 0; j < arr[i].props.children.length; j++) {
            heading += arr[i]?.props?.children[0];
          }
        } else heading += arr[i];
      }

      const slug = generateSlug(heading);
      return (
        <h1 id={slug}>
          <a href={`#${slug}`} {...props}></a>
        </h1>
      );
    },
    h2: (props: any) => {
      const arr = props.children;
      let heading = "";

      for (let i = 0; i < arr.length; i++) {
        if (arr[i]?.type !== undefined) {
          for (let j = 0; j < arr[i].props.children.length; j++) {
            heading += arr[i]?.props?.children[0];
          }
        } else heading += arr[i];
      }

      const slug = generateSlug(heading);
      return (
        <h2 id={slug}>
          <a href={`#${slug}`} {...props}></a>
        </h2>
      );
    },
    h3: (props: any) => {
      const arr = props.children;
      let heading = "";

      for (let i = 0; i < arr.length; i++) {
        if (arr[i]?.type !== undefined) {
          for (let j = 0; j < arr[i].props.children.length; j++) {
            heading += arr[i]?.props?.children[0];
          }
        } else heading += arr[i];
      }

      const slug = generateSlug(heading);
      return (
        <h3 id={slug} className="text-red-500">
          <a href={`#${slug}`} {...props}></a>
        </h3>
      );
    },
    h4: (props: any) => {
      const arr = props.children;
      let heading = "";

      for (let i = 0; i < arr.length; i++) {
        if (arr[i]?.type !== undefined) {
          for (let j = 0; j < arr[i].props.children.length; j++) {
            heading += arr[i]?.props?.children[0];
          }
        } else heading += arr[i];
      }

      const slug = generateSlug(heading);
      return (
        <h4 id={slug}>
          <a href={`#${slug}`} {...props}></a>
        </h4>
      );
    },
    code({ node, inline, className, ...props }: any) {
      
      const match = /language-(\w+)/.exec(className || "");
      const hasMeta = node?.data?.meta;


      const applyHighlights: object = (applyHighlights: number) => {
        if (hasMeta) {
          const RE = /{([\d,-]+)}/;
          const metadata = node.data.meta?.replace(/\s/g, "");
          const strlineNumbers = RE?.test(metadata)
            ? // @ts-ignore
              RE?.exec(metadata)[1]
            : "0";

          const highlightLines = rangeParser(strlineNumbers);
          const highlight = highlightLines;
          const data = highlight.includes(applyHighlights) ? "highlight" : null;
          return { data };
        } else {
          return {};
        }
      };

      const applyStartingNumber = () => {
        if (hasMeta) {
          const metadata = node.data.meta?.replace(/\s/g, "");
          const RE = /line=(\d+)/;
          const start = RE?.test(metadata) && RE.exec(metadata);
          return start ? +start[1] : 1;
        } else {
          return 1;
        }
      };

      const getTitle = () => {
        if (hasMeta) {
          const metadata = node.data.meta;
          const RE = /title=\"(.*)\"/;
          const title = RE?.test(metadata) && RE.exec(metadata);
          return title ? title[1] : "Code";
        }
        return "Code";
      };


      return match ? (
        <div>
          <div className="w-full flex flex-row items-center gap-4">
            <button
              className="w-fit ml-2 important"
              onClick={() => navigator.clipboard.writeText(props.children)}
            >
              <BiCopy />
            </button>
            {<div>{getTitle()}</div>}
          </div>
          <SyntaxHighlighter
            style={defaulttheme}
            language={match[1]}
            PreTag="div"
            className="codeStyle"
            showLineNumbers={true}
            wrapLines={hasMeta ? true : false}
            useInlineStyles={true}
            lineProps={applyHighlights}
            startingLineNumber={applyStartingNumber()}
            {...props}
          />
        </div>
      ) : (
        <code className={className} {...props} />
      );
    },
  };

  return (
    <div
      className="
        prose
        prose-code:font-mono prose-code:text-gray-100 prose-code:bg-gray-700 prose-code:p-1 prose-code:m-1 prose-code:rounded-md 
        prose-headings:text-gray-800 dark:prose-headings:text-gray-100 prose-p:text-gray-600 dark:prose-p:text-gray-300 
        prose-img:w-full prose-img:h-auto prose-img:object-cover 
        prose-li:text-gray-600 dark:prose-li:text-gray-300 prose-td:text-gray-600 dark:prose-td:text-gray-400 
      prose-a:text-primary prose-strong:text-gray-900 dark:prose-strong:text-gray-50
        dark:prose-hr:bg-gray-200 prose-hr:bg-gray-400
      "
    >
      <ReactMarkdown
        components={MarkdownComponents}
        rehypePlugins={[rehypeRaw]}
        remarkPlugins={[remarkGfm, remarkTypograf, smartypants, oembed, emoji]}
        children={html}
      />
    </div>
  );
};
