import type { ReactNode } from "react";
import { markdownToPortableText } from "./content-contract";

type PreviewBlock = ReturnType<typeof markdownToPortableText>[number];
type ListItemType = "bullet" | "number";
type PreviewListItem = { block: PreviewBlock; children: PreviewNode[] };
type PreviewNode =
  | { type: "block"; block: PreviewBlock }
  | { type: "list"; listItem: ListItemType; level: number; items: PreviewListItem[] };

function buildPreviewNodes(blocks: PreviewBlock[]): PreviewNode[] {
  const nodes: PreviewNode[] = [];
  const parentItems: PreviewListItem[] = [];

  for (const block of blocks) {
    if (block.listItem !== "bullet" && block.listItem !== "number") {
      parentItems.length = 0;
      nodes.push({ type: "block", block });
      continue;
    }

    let level = typeof block.level === "number" && Number.isFinite(block.level)
      ? Math.max(1, Math.min(6, Math.floor(block.level)))
      : 1;
    level = Math.min(level, parentItems.length + 1);
    const siblings = level === 1 ? nodes : parentItems[level - 2]?.children ?? nodes;
    const previous = siblings.at(-1);
    let list = previous?.type === "list" && previous.listItem === block.listItem && previous.level === level
      ? previous
      : null;

    if (!list) {
      list = { type: "list", listItem: block.listItem, level, items: [] };
      siblings.push(list);
    }

    const item: PreviewListItem = { block, children: [] };
    list.items.push(item);
    parentItems.length = level - 1;
    parentItems.push(item);
  }

  return nodes;
}

function renderInline(block: PreviewBlock): ReactNode[] {
  return block.children.map((span) => {
    let node: ReactNode = span.text;
    for (const mark of span.marks ?? []) {
      if (mark === "strong") node = <strong>{node}</strong>;
      if (mark === "em") node = <em>{node}</em>;
      if (mark === "code") node = <code className="rounded bg-muted px-1 py-0.5">{node}</code>;
    }
    return <span key={span._key} className="whitespace-pre-wrap">{node}</span>;
  });
}

function renderBlock(block: PreviewBlock, key: string): ReactNode {
  const children = renderInline(block);
  if (block.style === "h1") return <h1 key={key} className="text-2xl font-semibold leading-tight">{children}</h1>;
  if (block.style === "h2") return <h2 key={key} className="text-xl font-semibold leading-tight">{children}</h2>;
  if (block.style === "h3") return <h3 key={key} className="text-lg font-semibold leading-tight">{children}</h3>;
  if (block.style === "blockquote") return <blockquote key={key} className="border-l-2 pl-4 leading-7 text-muted-foreground">{children}</blockquote>;
  return <p key={key} className="text-sm leading-7 text-foreground/90">{children}</p>;
}

function renderNodes(nodes: PreviewNode[], path: string): ReactNode[] {
  return nodes.map((node, index) => {
    const key = `${path}${index}`;
    if (node.type === "block") return renderBlock(node.block, key);

    const Tag = node.listItem === "number" ? "ol" : "ul";
    const markerStyle = node.listItem === "number" ? "list-decimal" : "list-disc";
    return (
      <Tag key={key} className={`${markerStyle} space-y-1 pl-6 text-sm marker:font-medium marker:text-foreground/70`}>
        {node.items.map((item, itemIndex) => (
          <li key={`${key}-item-${itemIndex}`} className="pl-1 leading-7">
            {renderInline(item.block)}
            {item.children.length > 0 && (
              <div className="mt-2 space-y-3">
                {renderNodes(item.children, `${key}-${itemIndex}-`)}
              </div>
            )}
          </li>
        ))}
      </Tag>
    );
  });
}

export function MarkdownPreview({ value }: { value: string }) {
  const blocks = markdownToPortableText(value);
  if (blocks.length === 0) return <p className="text-sm text-muted-foreground">No content yet.</p>;

  return <div className="max-w-full space-y-3 break-words">{renderNodes(buildPreviewNodes(blocks), "preview-")}</div>;
}
