"use client";

import { Accordion, AccordionContent } from "@/lib/accordion";
import { Poppable } from "@/lib/poppables/components/poppable";
import { createElements } from "@/lib/tcmd";
import Link from "next/link";
import React, { FC, Fragment, ReactNode, use, useMemo } from "react";

import { sanitize } from "isomorphic-dompurify";
import StaticGenerationSearchParamsBailoutProvider from "next/dist/client/components/static-generation-searchparams-bailout-provider";

export const TTCMD: FC<{ body: Promise<string> }> = ({ body }) => {
  "use client";
  const text = use(body);
  const [elements, tabSpacing] = useMemo(() => createElements(text), [text]);
  const tada = useMemo(
    () => (
      <>{renderer(elements.filter((e) => !e.parent).map((e) => e.token!))}</>
    ),
    [elements],
  );
  return (
    <div className="text-lg col-span-2">
      <div>
        <button
          className="btn-primary"
          onClick={() =>
            navigator.clipboard.writeText(JSON.stringify(elements, null, 2))}
        >
          copy ast
        </button>
      </div>
      {/* {elements.map((e, i) => <Fragment key={e.uuid}>{render(e)}</Fragment>)} */}
      {tada}
    </div>
    // <div className="grid grid-cols-3">
    //   {/* <pre suppressHydrationWarning>{JSON.stringify(elements,null,2)}</pre> */}
    // </div>
  );
};

function renderer(tokens: Token[]) {
  const usedIds: string[] = [];
  return tokens.map((t) => (
    <div className="p" key={t.uuid}>{render(t, usedIds)}</div>
  ));
}

function render(token: Token, usedIds: string[]) {
  switch (token.type) {
    case "heading":
      return (
        <div
          id={generateId(token.raw, usedIds)}
          data-strength={token.metadata.strength}
          className={`
          font-bold
          data-[strength="1"]:text-4xl
          data-[strength="2"]:text-3xl
          data-[strength="3"]:text-2xl
          `}
        >
          {token.content}
        </div>
      );
    case "grid":
      return (
        <div
          style={{
            "--grid-cols": token.metadata.columns,
          } as React.CSSProperties}
          className="grid grid-cols-dynamic gap-x-8 gap-y-6 mb-6"
        >
          {token.children?.map((c, i) => (
            <div key={c.uuid}>
              {render(c, usedIds)}
            </div>
          ))}
        </div>
      );
    case "code":
      return (
        <pre className="whitespace-pre-wrap bg-black/20 p-2 rounded-md">
          {token.content}
        </pre>
      );
    case "card":
      return (
        <div className="card mb-6">
          {token.children?.map((e) => (
            <Fragment key={e.uuid}>
              {render(e, usedIds)}
            </Fragment>
          ))}
        </div>
      );
    case "anchor":
      return (
        <Link
          className={token.metadata.classes ||
            "dark:text-primary-600 underline dark:no-underline"}
          href={token.metadata.href}
        >
          {token.content}
        </Link>
      );
    case "image": {
      token.metadata.src = token.metadata.src as string;
      if (token.metadata.src.startsWith("<svg")) {
        return (
          <div
            dangerouslySetInnerHTML={{
              __html: sanitize(token.metadata.src, {
                USE_PROFILES: { svg: true },
              }),
            }}
          >
          </div>
        );
      }
      // eslint-disable-next-line @next/next/no-img-element
      return <img src={token.metadata.src} alt={token.content} />;
    }
    case "inline-code":
      return (
        <span className="p-1 rounded-md font-mono bg-black/20 border border-mixed-100/20 mx-2">
          {token.content}
        </span>
      );
    case "popover":
      return (
        <Poppable
          content={token.children?.map((c) => render(c, usedIds)) ||
            token.content}
          preferredAlign="centered"
          preferredEdge="bottom"
          className="cursor-pointer mx-2"
        >
          <span className="border-b-2 border-dotted border-white">
            {token.metadata.title}
          </span>
        </Poppable>
      );
    case "text":
      return (
        <span className="whitespace-pre-wrap">
          {token.content.replaceAll("\\n", "\n")}
        </span>
      );
    case "p":
      return (
        <div className="p">
          {token.children?.map((e, i) => (
            <Fragment key={e.uuid}>
              {render(e, usedIds)}
            </Fragment>
          ))}
        </div>
      );
    case "accordion":
      return (
        <div className="bg-black/20 p-1 rounded-md">
          <Accordion
            title={token.metadata.title || "Expand"}
          >
            <AccordionContent>
              {token.children?.map((e, i) => (
                <Fragment key={e.uuid}>
                  {render(e, usedIds)}
                </Fragment>
              ))}
            </AccordionContent>
          </Accordion>
        </div>
      );
    case "bold":
      return (
        <span className="font-bold">
          {token.content}
        </span>
      );
    case "italic":
      return (
        <span className="italic">
          {token.content}
        </span>
      );
    case "list":
      const items = token.children || [];
      return (
        <>
          <ul
            data-depth={(Number(token.metadata.initialDepth) / 2) % 3}
            className="data-[depth='2']:list-[circle] data-[depth='1']:list-[square] list-disc ml-6"
          >
            {items.map((c) => {
              return (
                <li
                  key={c.uuid}
                  data-depth={token.metadata.initialDepth}
                >
                  {c.children?.map((c) => render(c, usedIds))}
                </li>
              );
            })}
          </ul>
        </>
      );
    case "list-item":
      // This probably doesn't need to exist, but I'm leaving it anyway
      return (
        <li
          data-depth={token.metadata.initialDepth}
          className="ml-2"
        >
          {token.children?.map((c) => render(c, usedIds))}
        </li>
      );
    default:
      return (
        <div className="p bg-red-600 text-white">
          Block or paragraph missing implementation: {token.type}
        </div>
      );
  }
}

function generateId(t: string, usedIds: string[]) {
  let id = t.toLowerCase().replace(/[^a-z\s]/ig, "").trim().replaceAll(
    " ",
    "-",
  );
  let idNum = 1;
  while (usedIds.includes(id)) {
    id = id.replace(/-[0-9]+$/g, "");
    id += "-" + idNum;
    idNum++;
  }
  return id;
}
