"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 }) => {
  const text = use(body);
  const [elements, tabSpacing] = useMemo(() => createElements(text), [text]);
  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>)} */}
      {renderer(elements.map((e) => e.token!), tabSpacing)}
    </div>
    // <div className="grid grid-cols-3">
    //   {/* <pre suppressHydrationWarning>{JSON.stringify(elements,null,2)}</pre> */}
    // </div>
  );
};

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

const render = (token: Token, usedIds: string[], tabSpacing: number) => {
  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, tabSpacing)}
            </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, tabSpacing)}
            </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, tabSpacing)) ||
            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>{token.content}</span>;
    case "p":
      return (
        <div className="p">
          {token.children?.map((e, i) => (
            <Fragment key={e.uuid}>
              {render(e, usedIds, tabSpacing)}
            </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, tabSpacing)}
                </Fragment>
              ))}
            </AccordionContent>
          </Accordion>
        </div>
      );
    case "bold":
      return (
        <span className="font-bold">
          {token.content}
        </span>
      );
    case "italic":
      return (
        <span className="italic">
          {token.content}
        </span>
      );
    default:
      return (
        <div className="p bg-red-600 text-white">
          Block or paragraph missing implementation: {token.type}
        </div>
      );
  }
};

// const renderBlock = (
//   block: BlockChildren,
//   usedIds: string[] = [],
// ): ReactNode => {
//   usedIds = usedIds || [];
//   switch (block.type) {
//     case "block":
//       return block.children.map((e, i) => (
//         <Fragment key={e.uuid}>{renderBlock(e, usedIds)}</Fragment>
//       ));
//     case "grid":
//       return (
//         <div
//           style={{
//             "--grid-cols": block.metadata.columns,
//           } as React.CSSProperties}
//           className="grid grid-cols-dynamic gap-x-8 gap-y-6 mb-6"
//         >
//           {block.children.map((c, i) => (
//             <div key={c.uuid}>
//               {renderBlock(c, usedIds)}
//             </div>
//           ))}
//         </div>
//       );
//     case "card":
//       return (
//         <div className="card mb-6">
//           {block.children.map((e, i) => (
//             <Fragment key={e.uuid}>
//               {renderBlock(e, usedIds)}
//             </Fragment>
//           ))}
//         </div>
//       );
//     case "accordion":
//       return (
//         <div className="bg-black/20 p-1 rounded-md">
//           <Accordion
//             title={block.metadata.title || "Expand"}
//           >
//             <AccordionContent>
//               {block.children.map((e, i) => (
//                 <Fragment key={e.uuid}>
//                   {renderBlock(e, usedIds)}
//                 </Fragment>
//               ))}
//             </AccordionContent>
//           </Accordion>
//         </div>
//       );
//     default:
//       return (
//         renderParagraph(block as ParagraphToken, usedIds)
//       );
//   }
// };

// const renderParagraph = (p: ParagraphToken, usedIds: string[]) => {
//   switch (p.type) {
//     case "p":
//       return (
//         <div className="p">
//           {p.content.map((e, i) => (
//             <Fragment key={e.uuid}>
//               {renderToken(e, usedIds)}
//             </Fragment>
//           ))}
//         </div>
//       );
//     case "code":
//       return (
//         <pre className="whitespace-pre-wrap bg-black/20 p-2 rounded-md">
//           {p.content.map((c) => c.line.toString()).join("\n\n")}
//         </pre>
//       );
//     default:
//       return (
//         <div className="p bg-red-600 text-white">
//           Block or paragraph missing implementation: {p.type}
//         </div>
//       );
//   }
// };

const 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;
};

// const renderToken = (t: Token, usedIds: string[]) => {
//   switch (t.type) {
//     case "h1": {
//       return (
//         <div
//           id={generateId(t.raw, usedIds)}
//           className="font-bold text-2xl p"
//         >
//           {renderInlineToken(t.line)}
//         </div>
//       );
//     }
//     case "h2": {
//       return (
//         <div
//           id={generateId(t.raw, usedIds)}
//           className="font-bold text-xl p"
//         >
//           {renderInlineToken(t.line)}
//         </div>
//       );
//     }
//     case "h3": {
//       return (
//         <div
//           id={generateId(t.raw, usedIds)}
//           className="font-bold text-lg p"
//         >
//           {renderInlineToken(t.line)}
//         </div>
//       );
//     }
//     case "p":
//       return (
//         <div className="p">
//           {t.lines.map((e, i) => (
//             <Fragment key={e.uuid}>
//               {renderInlineToken(e.line)}
//             </Fragment>
//           ))}
//         </div>
//       );
//     case "text":
//       return (
//         <>
//           {renderInlineToken(t.line)}
//           &nbsp;
//         </>
//       );
//     case "list1":
//       return <li className="list-disc ml-6">{renderInlineToken(t.line)}</li>;
//     case "list2":
//       return <li className="list-disc ml-12">{renderInlineToken(t.line)}</li>;
//     default:
//       return (
//         <div className="text-white bg-red-500 p">
//           Missing implementation for tcMD element `{(t as { type: string })
//             .type}`
//         </div>
//       );
//   }
// };

// const renderInlineToken = (l: Line) => {
//   if (typeof l === "string") return l;

//   return l.map((token) => (
//     <Fragment key={token.uuid}>
//       {(() => {
//         switch (token.type) {
//           case "text":
//             return <span>{token.content}</span>;
//           case "bold":
//             return <span className="font-bold">{token.content}</span>;
//           case "italic":
//             return <span className="italic">{token.content}</span>;
//           case "anchor":
//             return (
//               <Link
//                 className={token.data.style?.classes ||
//                   "dark:text-primary-600 underline dark:no-underline"}
//                 href={token.data.href}
//               >
//                 {token.content}
//               </Link>
//             );
//           case "image": {
//             token.data.src = token.data.src as string;
//             if (token.data.src.startsWith("<svg")) {
//               return (
//                 <div
//                   dangerouslySetInnerHTML={{
//                     __html: sanitize(token.data.src, {
//                       USE_PROFILES: { svg: true },
//                     }),
//                   }}
//                 >
//                 </div>
//               );
//             }
//             // eslint-disable-next-line @next/next/no-img-element
//             return <img src={token.data.src} alt={token.content} />;
//           }
//           case "popover":
//             return (
//               <Poppable
//                 content={renderInlineToken(token.data.popover)}
//                 preferredAlign="centered"
//                 preferredEdge="bottom"
//                 className="cursor-pointer"
//               >
//                 <span className="border-b-2 border-dotted border-white">
//                   {token.content}
//                 </span>
//               </Poppable>
//             );
//           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>
//             );
//           default:
//             return (
//               <span className="bg-red-500">
//                 Inline element not implemented: {token.type}
//               </span>
//             );
//         }
//       })()}
//     </Fragment>
//   ));
// };
