import type { ReactNode } from "react";
import type { RichTextMark, RichTextNode } from "@slackwsh/core";
import { sanitizeMessageBlocks } from "@slackwsh/core";

interface RichTextMessageProps {
  blocks: unknown;
  fallback: string;
  className: string;
  renderText: (text: string) => ReactNode;
}

function markedText(text: string, marks: RichTextMark[] | undefined, renderText: (text: string) => ReactNode, key: string): ReactNode {
  let result: ReactNode = renderText(text);
  for (const [index, mark] of (marks ?? []).entries()) {
    const markKey = `${key}-mark-${index}`;
    if (mark.type === "bold") result = <strong key={markKey}>{result}</strong>;
    else if (mark.type === "italic") result = <em key={markKey}>{result}</em>;
    else if (mark.type === "underline") result = <u key={markKey}>{result}</u>;
    else if (mark.type === "strike") result = <s key={markKey}>{result}</s>;
    else if (mark.type === "code") result = <code className="msg-code" key={markKey}>{result}</code>;
    else if (mark.type === "link" && mark.attrs?.href) {
      result = <a key={markKey} href={mark.attrs.href} target="_blank" rel="noopener noreferrer">{result}</a>;
    }
  }
  return result;
}

function renderNode(node: RichTextNode, renderText: (text: string) => ReactNode, key: string): ReactNode {
  if (node.type === "text") return markedText(node.text ?? "", node.marks, renderText, key);
  if (node.type === "hardBreak") return <br key={key} />;
  const children = (node.content ?? []).map((child, index) => renderNode(child, renderText, `${key}-${index}`));
  if (node.type === "paragraph") return <p key={key}>{children.length ? children : <br />}</p>;
  if (node.type === "heading") {
    const level = node.attrs?.level ?? 1;
    return level === 3 ? <h3 key={key}>{children}</h3> : level === 2 ? <h2 key={key}>{children}</h2> : <h1 key={key}>{children}</h1>;
  }
  if (node.type === "bulletList") return <ul key={key}>{children}</ul>;
  if (node.type === "orderedList") return <ol key={key} start={node.attrs?.start}>{children}</ol>;
  if (node.type === "listItem") return <li key={key}>{children}</li>;
  if (node.type === "blockquote") return <blockquote key={key}>{children}</blockquote>;
  if (node.type === "codeBlock") return <pre key={key}><code>{children}</code></pre>;
  return <>{children}</>;
}

function hasRichFormatting(node: unknown): boolean {
  if (!node || typeof node !== "object") return false;
  const value = node as Record<string, unknown>;
  if (value.type !== "doc" && value.type !== "paragraph" && value.type !== "text") return true;
  if (Array.isArray(value.marks) && value.marks.length > 0) return true;
  return Array.isArray(value.content) && value.content.some(hasRichFormatting);
}

export function RichTextMessage({ blocks, fallback, className, renderText }: RichTextMessageProps) {
  const safe = sanitizeMessageBlocks(blocks, fallback);
  const doc = safe.doc as unknown as RichTextNode;
  if (!hasRichFormatting(doc)) return <p className={className}>{renderText(fallback)}</p>;
  return <div className={`${className} rich-message`}>{renderNode(doc, renderText, "doc")}</div>;
}
