"use client";

import { Fragment, type ReactNode } from "react";

type BlogRichBlockKind =
  | "audio"
  | "breadcrumb"
  | "button"
  | "callout"
  | "columns-2"
  | "columns-3"
  | "columns-4"
  | "database-board"
  | "database-calendar"
  | "database-chart"
  | "database-gallery"
  | "database-list"
  | "database-table"
  | "database-timeline"
  | "file"
  | "math"
  | "mermaid"
  | "page"
  | "table"
  | "tabs"
  | "toc"
  | "toggle"
  | "toggle-heading1"
  | "toggle-heading2"
  | "toggle-heading3"
  | "video";

type BlogRichBlock = {
  body: string;
  kind: BlogRichBlockKind;
  title: string;
  url: string;
};

const BLOG_RICH_BLOCK_KINDS: BlogRichBlockKind[] = [
  "audio", "breadcrumb", "button", "callout", "columns-2", "columns-3", "columns-4",
  "database-board", "database-calendar", "database-chart", "database-gallery", "database-list",
  "database-table", "database-timeline", "file", "math", "mermaid", "table", "tabs", "toc",
  "page", "toggle", "toggle-heading1", "toggle-heading2", "toggle-heading3", "video",
];

function safeLinkHref(value: string) {
  const trimmed = value.trim();

  if (trimmed.startsWith("/") || trimmed.startsWith("#")) {
    return trimmed;
  }

  try {
    const url = new URL(trimmed);
    return ["https:", "http:", "mailto:"].includes(url.protocol) ? trimmed : null;
  } catch {
    return null;
  }
}

function clampPercentage(value: unknown, fallback: number, minimum: number, maximum: number) {
  const parsed = typeof value === "number" ? value : Number(value);

  if (!Number.isFinite(parsed)) return fallback;

  return Math.round(Math.min(maximum, Math.max(minimum, parsed)));
}

function parseMarkdownImage(value: string) {
  const match = value.match(
    /^!\[([^\]]*)\]\(((?:https?:\/\/|\/(?!\/))[^\s)]+)\)(?:\{width=(\d{1,3})(?:;align=(left|center|right))?\})?$/,
  );

  if (!match) {
    return null;
  }

  const src = safeLinkHref(match[2]);

  return src
    ? {
      alt: match[1],
      align: (match[4] as "left" | "center" | "right" | undefined) ?? "center",
      src,
      width: clampPercentage(match[3], 100, 28, 100),
    }
    : null;
}

function parseImageGridStart(value: string) {
  const match = value.match(/^:::image-grid(?:\{left=(\d{1,3})\})?$/);

  return match ? clampPercentage(match[1], 50, 25, 75) : null;
}

function parseColumnLayoutStart(value: string) {
  const match = value.match(/^:::columns(?:\{left=(\d{1,3})(?:;styles=[a-z]+,[a-z]+)?\})?$/);
  return match ? clampPercentage(match[1], 50, 25, 75) : null;
}

function parseColumnLayout(lines: string[], startIndex: number) {
  const split = parseColumnLayoutStart(lines[startIndex].trim());

  if (split === null || lines[startIndex + 1]?.trim() !== ":::column-left") return null;

  const rightIndex = lines.findIndex((line, index) => index > startIndex + 1 && line.trim() === ":::column-right");
  const endIndex = lines.findIndex((line, index) => index > rightIndex && line.trim() === ":::columns-end");

  if (rightIndex < 0 || endIndex < 0) return null;

  return {
    columns: [
      lines.slice(startIndex + 2, rightIndex).join("\n").trim(),
      lines.slice(rightIndex + 1, endIndex).join("\n").trim(),
    ] as [string, string],
    nextIndex: endIndex + 1,
    split,
  };
}

function parseRichBlock(lines: string[], startIndex: number) {
  const match = lines[startIndex]?.trim().match(
    /^:::official-block\{type=([a-z0-9-]+);title=([^;]*);url=([^}]*)\}$/,
  );

  if (!match || !BLOG_RICH_BLOCK_KINDS.includes(match[1] as BlogRichBlockKind)) return null;

  const endIndex = lines.findIndex(
    (line, index) => index > startIndex && line.trim() === ":::official-block-end",
  );

  if (endIndex < 0) return null;

  try {
    return {
      block: {
        body: lines.slice(startIndex + 1, endIndex).join("\n"),
        kind: match[1] as BlogRichBlockKind,
        title: decodeURIComponent(match[2]),
        url: decodeURIComponent(match[3]),
      } satisfies BlogRichBlock,
      nextIndex: endIndex + 1,
    };
  } catch {
    return null;
  }
}

function renderInline(value: string): ReactNode[] {
  const tokenPattern = /(\*\*[^*]+\*\*|\*[^*]+\*|~~[^~]+~~|==[^=]+==|`[^`]+`|\[[^\]]+\]\([^\s)]+\))/g;
  const tokens = value.split(tokenPattern);

  return tokens.map((token, index) => {
    if (token.startsWith("**") && token.endsWith("**")) {
      return (
        <strong key={`${token}-${index}`} className="font-semibold text-[#243555]">
          {renderInline(token.slice(2, -2))}
        </strong>
      );
    }

    if (token.startsWith("*") && token.endsWith("*")) {
      return <em key={`${token}-${index}`}>{renderInline(token.slice(1, -1))}</em>;
    }

    if (token.startsWith("~~") && token.endsWith("~~")) {
      return <s key={`${token}-${index}`}>{renderInline(token.slice(2, -2))}</s>;
    }

    if (token.startsWith("==") && token.endsWith("==")) {
      return (
        <u key={`${token}-${index}`} className="decoration-[#6f8fc7] underline-offset-2">
          {renderInline(token.slice(2, -2))}
        </u>
      );
    }

    if (token.startsWith("`") && token.endsWith("`")) {
      return (
        <code key={`${token}-${index}`} className="rounded bg-[#f2f5fa] px-1.5 py-0.5 font-mono text-[0.9em] text-[#38527a]">
          {token.slice(1, -1)}
        </code>
      );
    }

    const linkMatch = token.match(/^\[([^\]]+)\]\(([^\s)]+)\)$/);

    if (linkMatch) {
      const href = safeLinkHref(linkMatch[2]);

      if (href) {
        return (
          <a
            key={`${token}-${index}`}
            href={href}
            target={href.startsWith("http") ? "_blank" : undefined}
            rel={href.startsWith("http") ? "noreferrer" : undefined}
            className="font-semibold text-[#2f6df6] underline decoration-[#b7d0ff] underline-offset-4 transition-colors hover:text-[#174fca]"
          >
            {linkMatch[1]}
          </a>
        );
      }
    }

    return <Fragment key={`${token}-${index}`}>{token}</Fragment>;
  });
}

function isTableDivider(value: string) {
  return /^\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?$/.test(value.trim());
}

function tableCells(value: string) {
  return value
    .trim()
    .replace(/^\||\|$/g, "")
    .split("|")
    .map((cell) => cell.trim());
}

function richTableColumnWidths(value: string, columnCount: number) {
  const match = value.match(/^table-widths:([\d.,]+)$/);
  const widths = match?.[1].split(",").map(Number);

  if (!widths || widths.length !== columnCount || widths.some((width) => !Number.isFinite(width) || width < 8)) {
    return Array.from({ length: columnCount }, () => 100 / Math.max(1, columnCount));
  }

  const total = widths.reduce((sum, width) => sum + width, 0);
  return widths.map((width) => width / total * 100);
}

function richColumnWidths(value: string, columnCount: number) {
  const match = value.match(/^column-widths:([\d.,]+)$/);
  const widths = match?.[1].split(",").map(Number);

  if (!widths || widths.length !== columnCount || widths.some((width) => !Number.isFinite(width) || width < 10)) {
    return Array.from({ length: columnCount }, () => 100 / Math.max(1, columnCount));
  }

  const total = widths.reduce((sum, width) => sum + width, 0);
  return widths.map((width) => width / total * 100);
}

function recoverRichColumnsFromLegacyLayout(layout: { columns: [string, string]; split: number }) {
  const parsedColumns = layout.columns.map((column) => {
    const lines = column.replace(/\r/g, "").split("\n");
    const parsed = parseRichBlock(lines, 0);

    return parsed?.block?.kind.startsWith("columns-") && parsed.nextIndex === lines.length
      ? parsed.block
      : null;
  });
  const nestedIndex = parsedColumns.findIndex(Boolean);

  if (nestedIndex < 0 || parsedColumns.filter(Boolean).length !== 1) return null;

  const nested = parsedColumns[nestedIndex]!;
  const nestedCount = Number(nested.kind.slice(-1));
  const nestedValues = Array.from(
    { length: nestedCount },
    (_, index) => nested.body.split("\n")[index] ?? "",
  );
  const plain = layout.columns[nestedIndex === 0 ? 1 : 0].trim();
  const count = nestedCount + 1;

  if (!plain || plain.includes("\n") || count > 4) return null;

  const nestedShare = nestedIndex === 0 ? layout.split : 100 - layout.split;
  const plainShare = 100 - nestedShare;
  const nestedWidths = richColumnWidths(nested.url, nestedCount)
    .map((width) => width * nestedShare / 100);
  let widths = nestedIndex === 0
    ? [...nestedWidths, plainShare]
    : [plainShare, ...nestedWidths];

  if (widths.some((width) => width < 10)) {
    widths = Array.from({ length: count }, () => 100 / count);
  }

  return {
    body: nestedIndex === 0
      ? [...nestedValues, plain].join("\n")
      : [plain, ...nestedValues].join("\n"),
    kind: `columns-${count}` as BlogRichBlockKind,
    title: `${count}개의 열`,
    url: `column-widths:${widths.map((width) => Math.round(width * 100) / 100).join(",")}`,
  } satisfies BlogRichBlock;
}

function richVideoSettings(value: string) {
  const [firstLine = "", ...captionLines] = value.split("\n");
  const match = firstLine.match(/^video-settings:width=(\d{1,3});align=(left|center|right)$/);

  if (!match) {
    return {
      align: "center",
      caption: value.trim(),
      width: 100,
    };
  }

  return {
    align: match[2],
    caption: captionLines.join("\n").trim(),
    width: clampPercentage(match[1], 100, 28, 100),
  };
}

function renderRichBlock(block: BlogRichBlock, headings: string[], key: string) {
  const lines = block.body.split("\n").map((line) => line.trim()).filter(Boolean);
  const safeUrl = safeLinkHref(block.url);

  if (block.kind === "toc") {
    return (
      <nav key={key} aria-label="글 목차" className="my-8 border-y border-[#e7edf7] py-5 xl:hidden">
        <p className="text-[13px] font-semibold text-[#26364f]">목차</p>
        <ol className="mt-3 space-y-2 text-[14px] text-[#60718b]">
          {headings.map((heading, index) => <li key={`${heading}-${index}`}>{String(index + 1).padStart(2, "0")}. {heading}</li>)}
        </ol>
      </nav>
    );
  }

  if (block.kind.startsWith("toggle")) {
    const headingClass = block.kind === "toggle-heading1"
      ? "text-[26px] sm:text-[32px]"
      : block.kind === "toggle-heading2"
        ? "text-[21px] sm:text-[25px]"
        : block.kind === "toggle-heading3"
          ? "text-[18px] sm:text-[20px]"
          : "text-[16px]";
    return (
      <details key={key} open={block.url === "toggle-open:1"} className="group my-7 border-y border-[#e7edf7] py-4">
        <summary className={`${headingClass} cursor-pointer font-semibold tracking-[-0.04em] text-[#26364f]`}>{block.title}</summary>
        <p className="mt-4 pl-5 text-[16px] leading-8 text-[#5b6b82]">{renderInline(block.body)}</p>
      </details>
    );
  }

  if (block.kind === "callout") {
    return (
      <aside key={key} className="my-7 grid grid-cols-[auto_minmax(0,1fr)] gap-3 rounded-[10px] bg-[#f5f7fa] px-4 py-4">
        <span>{block.title || "💡"}</span>
        <p className="text-[15px] leading-7 text-[#526784]">{renderInline(block.body)}</p>
      </aside>
    );
  }

  if (block.kind === "table" || block.kind === "database-table") {
    const rows = lines.map(tableCells);
    const headers = rows.shift() ?? [];
    const widths = richTableColumnWidths(block.url, headers.length);
    return (
      <div key={key} className="my-8 overflow-x-auto border-y border-[#e7edf7]">
        {block.title ? <p className="px-3 pb-2 pt-4 text-[14px] font-semibold text-[#26364f] sm:px-4">{block.title}</p> : null}
        <table className="w-full min-w-[560px] border-collapse text-left text-[13px] leading-6">
          <colgroup>{widths.map((width, index) => <col key={index} style={{ width: `${width}%` }} />)}</colgroup>
          <thead className="border-y border-[#e7edf7] bg-[#f8faff] text-[#526784]"><tr>{headers.map((cell, index) => <th key={`${cell}-${index}`} className="px-3 py-2.5 font-semibold sm:px-4">{renderInline(cell)}</th>)}</tr></thead>
          <tbody>{rows.map((row, rowIndex) => <tr key={rowIndex} className="border-b border-[#edf2f8] last:border-b-0">{headers.map((_, cellIndex) => <td key={cellIndex} className="px-3 py-3 text-[#60718b] sm:px-4">{renderInline(row[cellIndex] ?? "")}</td>)}</tr>)}</tbody>
        </table>
      </div>
    );
  }

  if (block.kind === "database-chart") {
    const points = lines.map((line) => {
      const [label, rawValue] = line.split(":");
      return { label: label?.trim() || "항목", value: Math.max(0, Math.min(100, Number(rawValue) || 0)) };
    });
    return (
      <section key={key} className="my-8 border-y border-[#e7edf7] py-5">
        <p className="text-[14px] font-semibold text-[#26364f]">{block.title}</p>
        <div className="mt-4 space-y-3">{points.map((point, index) => <div key={`${point.label}-${index}`} className="grid grid-cols-[90px_minmax(0,1fr)_38px] items-center gap-3 text-[12px] text-[#60718b]"><span className="truncate">{point.label}</span><span className="h-2 overflow-hidden rounded-full bg-[#edf1f6]"><span className="block h-full rounded-full bg-[#2f6df6]" style={{ width: `${point.value}%` }} /></span><span className="text-right">{point.value}</span></div>)}</div>
      </section>
    );
  }

  if (block.kind.startsWith("database-")) {
    const gallery = block.kind === "database-gallery" || block.kind === "database-board";
    return (
      <section key={key} className="my-8 border-y border-[#e7edf7] py-5">
        <p className="text-[14px] font-semibold text-[#26364f]">{block.title}</p>
        <div className={`mt-4 ${gallery ? "grid gap-3 sm:grid-cols-3" : "divide-y divide-[#edf1f6]"}`}>
          {lines.map((line, index) => {
            const [title, status] = line.split("::").map((part) => part.trim());
            return (
              <div key={`${line}-${index}`} className={gallery ? "rounded-[9px] border border-[#e3e8ef] px-3 py-4 text-[13px] text-[#60718b]" : "py-3 text-[14px] text-[#60718b]"}>
                {renderInline(title)}
                {block.kind === "database-board" && status ? <span className="mt-2 block text-[11px] text-[#8a98ae]">{status}</span> : null}
              </div>
            );
          })}
        </div>
      </section>
    );
  }

  if (block.kind.startsWith("columns-")) {
    const count = Number(block.kind.slice(-1));
    const widths = richColumnWidths(block.url, count);
    return (
      <div key={key} className="my-8 grid gap-5 max-sm:!grid-cols-1" style={{ gridTemplateColumns: widths.map((width) => `minmax(0, ${width}fr)`).join(" ") }}>
        {Array.from({ length: count }, (_, index) => <div key={index} className="min-w-0 text-[15px] leading-7 text-[#60718b]">{renderInline(lines[index] ?? "")}</div>)}
      </div>
    );
  }

  if (block.kind === "tabs") {
    return (
      <div key={key} className="my-8 border-y border-[#e7edf7] py-4">
        {lines.map((line, index) => {
          const [title, ...content] = line.split("|");
          return <details key={`${title}-${index}`} open={index === 0} className="border-b border-[#edf1f6] py-3 last:border-b-0"><summary className="cursor-pointer text-[14px] font-semibold text-[#26364f]">{title.trim()}</summary><p className="mt-2 text-[14px] leading-7 text-[#60718b]">{renderInline(content.join("|").trim())}</p></details>;
        })}
      </div>
    );
  }

  if (block.kind === "button") {
    return safeUrl ? <a key={key} href={safeUrl} target={safeUrl.startsWith("http") ? "_blank" : undefined} rel="noreferrer" className="my-7 inline-flex h-11 items-center rounded-[10px] bg-[#2f6df6] px-5 text-[14px] font-semibold text-white">{block.title}</a> : null;
  }

  if (block.kind === "video" && safeUrl?.startsWith("http")) {
    const settings = richVideoSettings(block.body);
    return (
      <figure
        key={key}
        className={`blog-markdown-video my-8 ${settings.align === "left" ? "mr-auto" : settings.align === "right" ? "ml-auto" : "mx-auto"}`}
        style={{ width: `${settings.width}%` }}
      >
        <video controls playsInline preload="metadata" src={safeUrl} className="w-full rounded-[12px] bg-[#111827]" />
        {settings.caption ? <figcaption className="mt-2 text-center text-[12px] text-[#8492a6]">{settings.caption}</figcaption> : null}
      </figure>
    );
  }

  if (block.kind === "audio" && safeUrl?.startsWith("http")) {
    return <figure key={key} className="my-8"><figcaption className="mb-2 text-[14px] font-semibold text-[#26364f]">{block.title}</figcaption><audio controls src={safeUrl} className="w-full" /><p className="mt-2 text-[12px] text-[#8492a6]">{block.body}</p></figure>;
  }

  if (block.kind === "file") {
    return safeUrl ? <a key={key} href={safeUrl} target="_blank" rel="noreferrer" className="my-7 flex items-center justify-between border-y border-[#e7edf7] py-4 text-[14px] font-semibold text-[#26364f]"><span>{block.title}</span><span className="text-[#2f6df6]">파일 열기 ↗</span></a> : null;
  }

  if (block.kind === "page") {
    return safeUrl ? <a key={key} href={safeUrl} className="my-5 flex items-center gap-3 rounded-[8px] px-2 py-3 text-[15px] font-semibold text-[#26364f] transition-colors hover:bg-[#f5f7fa]"><span aria-hidden="true" className="text-[#8492a6]">▤</span><span>{block.title}</span></a> : null;
  }

  if (block.kind === "breadcrumb") {
    const crumbs = block.body.split("/");
    return <nav key={key} className="my-7 flex flex-wrap items-center gap-2 text-[12px] text-[#8290a6]">{crumbs.map((item, index) => <Fragment key={`${item}-${index}`}><span>{item.trim()}</span>{index < crumbs.length - 1 ? <span>/</span> : null}</Fragment>)}</nav>;
  }

  if (block.kind === "math" || block.kind === "mermaid") {
    return <div key={key} className="my-7 overflow-x-auto rounded-[10px] bg-[#f4f6f9] px-4 py-4"><p className="mb-2 text-[11px] font-semibold text-[#8190a6]">{block.title}</p><pre className="m-0 whitespace-pre-wrap font-mono text-[13px] leading-6 text-[#344767]">{block.body}</pre></div>;
  }

  return null;
}

function isBlockStart(value: string) {
  const line = value.trim();
  return (
    !line ||
    /^:::official-block\{/.test(line) ||
    /^#{1,4}\s+/.test(line) ||
    /^[-*]\s+\[[ xX]\]\s+/.test(line) ||
    /^[-*]\s+/.test(line) ||
    /^\d+\.\s+/.test(line) ||
    /^>\s?/.test(line) ||
    /^```/.test(line) ||
    Boolean(parseMarkdownImage(line)) ||
    parseImageGridStart(line) !== null ||
    parseColumnLayoutStart(line) !== null ||
    /^---+$/.test(line) ||
    line.startsWith("|")
  );
}

export function MarkdownPreview({
  className = "",
  content,
  inlineContent = null,
  inlineContentAfterParagraph = 2,
}: {
  className?: string;
  content: string;
  inlineContent?: ReactNode;
  inlineContentAfterParagraph?: number;
}) {
  const lines = content.replace(/\r\n/g, "\n").split("\n");
  const headings = lines
    .map((line) => line.trim().match(/^##\s+(.+)$/)?.[1] ?? "")
    .filter(Boolean);
  const blocks: ReactNode[] = [];
  let index = 0;
  let paragraphCount = 0;

  while (index < lines.length) {
    const rawLine = lines[index];
    const line = rawLine.trim();

    if (!line) {
      index += 1;
      continue;
    }

    const columnLayout = parseColumnLayout(lines, index);

    if (columnLayout) {
      const recoveredColumns = recoverRichColumnsFromLegacyLayout(columnLayout);

      if (recoveredColumns) {
        blocks.push(renderRichBlock(recoveredColumns, headings, `rich-${blocks.length}`));
        index = columnLayout.nextIndex;
        continue;
      }

      blocks.push(
        <div
          key={`columns-${blocks.length}`}
          className="blog-markdown-columns my-9"
          style={{ gridTemplateColumns: `${columnLayout.split}fr ${100 - columnLayout.split}fr` }}
        >
          {columnLayout.columns.map((column, columnIndex) => (
            <div key={`column-${columnIndex}`} className="min-w-0">
              <MarkdownPreview content={column} />
            </div>
          ))}
        </div>,
      );
      index = columnLayout.nextIndex;
      continue;
    }

    const richBlock = parseRichBlock(lines, index);

    if (richBlock) {
      blocks.push(renderRichBlock(richBlock.block, headings, `rich-${blocks.length}`));
      index = richBlock.nextIndex;
      continue;
    }

    if (line.startsWith("```")) {
      const language = line.slice(3).trim();
      const codeLines: string[] = [];
      index += 1;

      while (index < lines.length && !lines[index].trim().startsWith("```")) {
        codeLines.push(lines[index]);
        index += 1;
      }

      if (index < lines.length) {
        index += 1;
      }

      blocks.push(
        <div key={`code-${blocks.length}`} className="my-7 overflow-x-auto rounded-[12px] bg-[#16233c] px-4 py-4 text-[#e7efff]">
          {language ? <p className="mb-2 text-[11px] font-semibold uppercase tracking-[0.12em] text-[#94b9ff]">{language}</p> : null}
          <pre className="m-0 whitespace-pre-wrap font-mono text-[13px] leading-6">{codeLines.join("\n")}</pre>
        </div>,
      );
      continue;
    }

    const imageGridSplit = parseImageGridStart(line);

    if (
      imageGridSplit !== null &&
      index + 3 < lines.length &&
      lines[index + 3].trim() === ":::") {
      const leftImage = parseMarkdownImage(lines[index + 1].trim());
      const rightImage = parseMarkdownImage(lines[index + 2].trim());

      if (leftImage && rightImage) {
        blocks.push(
          <div
            key={`image-grid-${blocks.length}`}
            className="blog-markdown-image-grid my-9"
            style={{ gridTemplateColumns: `${imageGridSplit}fr ${100 - imageGridSplit}fr` }}
          >
            {[leftImage, rightImage].map((image, imageIndex) => (
              <figure key={`${image.src}-${imageIndex}`}>
                {/* The NCP CDN domain is configured at runtime, so next/image cannot safely preconfigure this source. */}
                {/* eslint-disable-next-line @next/next/no-img-element */}
                <img
                  src={image.src}
                  alt={image.alt}
                  className="h-auto w-full rounded-[14px] border border-[#e3eaf4] bg-[#f7faff] shadow-[0_16px_40px_rgba(23,44,82,0.1)]"
                />
                {image.alt ? <figcaption className="mt-2 text-center text-[12px] leading-5 text-[#8492a6]">{image.alt}</figcaption> : null}
              </figure>
            ))}
          </div>,
        );
        index += 4;
        continue;
      }
    }

    const image = parseMarkdownImage(line);

    if (image) {
      blocks.push(
        <figure
          key={`image-${blocks.length}`}
          className={`blog-markdown-image-single my-9 ${
            image.align === "left" ? "mr-auto" : image.align === "right" ? "ml-auto" : "mx-auto"
          }`}
          style={{ width: `${image.width}%` }}
        >
          {/* The NCP CDN domain is configured at runtime, so next/image cannot safely preconfigure this source. */}
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img
            src={image.src}
            alt={image.alt}
            className="h-auto w-full rounded-[14px] border border-[#e3eaf4] bg-[#f7faff] shadow-[0_16px_40px_rgba(23,44,82,0.1)]"
          />
          {image.alt ? <figcaption className="mt-2 text-center text-[12px] leading-5 text-[#8492a6]">{image.alt}</figcaption> : null}
        </figure>,
      );
      index += 1;
      continue;
    }

    if (line.startsWith("|") && index + 1 < lines.length && isTableDivider(lines[index + 1])) {
      const headers = tableCells(line);
      const rows: string[][] = [];
      index += 2;

      while (index < lines.length && lines[index].trim().startsWith("|")) {
        rows.push(tableCells(lines[index]));
        index += 1;
      }

      blocks.push(
        <div key={`table-${blocks.length}`} className="my-8 overflow-x-auto border-y border-[#e7edf7]">
          <table className="w-full min-w-[560px] border-collapse text-left text-[13px] leading-6">
            <thead className="border-b border-[#e7edf7] bg-[#f8faff] text-[#526784]">
              <tr>
                {headers.map((header, cellIndex) => (
                  <th key={`${header}-${cellIndex}`} className="px-3 py-2.5 font-semibold sm:px-4">
                    {renderInline(header)}
                  </th>
                ))}
              </tr>
            </thead>
            <tbody className="text-[#526784]">
              {rows.map((row, rowIndex) => (
                <tr key={`row-${rowIndex}`} className="border-b border-[#edf2f8] last:border-b-0">
                  {headers.map((_, cellIndex) => (
                    <td key={`cell-${rowIndex}-${cellIndex}`} className="px-3 py-3 align-top sm:px-4">
                      {renderInline(row[cellIndex] ?? "")}
                    </td>
                  ))}
                </tr>
              ))}
            </tbody>
          </table>
        </div>,
      );
      continue;
    }

    const heading = line.match(/^(#{1,4})\s+(.+)$/);

    if (heading) {
      const level = heading[1].length;
      const headingClass =
        level === 1
          ? "mt-12 text-[30px] font-semibold leading-[1.18] tracking-[-0.065em] text-[#16233c] sm:text-[40px]"
          : level === 2
            ? "mt-14 scroll-mt-28 text-[25px] font-semibold leading-[1.24] tracking-[-0.055em] text-[#16233c] sm:text-[32px]"
            : level === 3
              ? "mt-10 text-[19px] font-semibold leading-8 tracking-[-0.04em] text-[#243555] sm:text-[21px]"
              : "mt-8 text-[16px] font-semibold leading-7 tracking-[-0.03em] text-[#344767] sm:text-[18px]";
      const Tag = level === 1 ? "h1" : level === 2 ? "h2" : level === 3 ? "h3" : "h4";

      blocks.push(
        <Tag key={`heading-${blocks.length}`} className={headingClass}>
          {renderInline(heading[2])}
        </Tag>,
      );
      index += 1;
      continue;
    }

    if (/^---+$/.test(line)) {
      blocks.push(<hr key={`rule-${blocks.length}`} className="my-10 border-0 border-t border-[#e8eef7]" />);
      index += 1;
      continue;
    }

    if (line.startsWith(">")) {
      const quoteLines: string[] = [];

      while (index < lines.length && lines[index].trim().startsWith(">")) {
        quoteLines.push(lines[index].trim().replace(/^>\s?/, ""));
        index += 1;
      }

      blocks.push(
        <aside key={`quote-${blocks.length}`} className="my-8 border-l-2 border-[#2f6df6] bg-[#f7faff] px-4 py-4 sm:px-5">
          {quoteLines.map((quote, quoteIndex) => (
            <p key={`${quote}-${quoteIndex}`} className={`text-[14px] leading-7 text-[#4f6280] ${quoteIndex > 0 ? "mt-1" : ""}`}>
              {renderInline(quote)}
            </p>
          ))}
        </aside>,
      );
      continue;
    }

    if (/^[-*]\s+\[[ xX]\]\s+/.test(line)) {
      const items: Array<{ checked: boolean; text: string }> = [];

      while (index < lines.length && /^[-*]\s+\[[ xX]\]\s+/.test(lines[index].trim())) {
        const item = lines[index].trim();
        items.push({
          checked: /^[-*]\s+\[[xX]\]/.test(item),
          text: item.replace(/^[-*]\s+\[[ xX]\]\s+/, ""),
        });
        index += 1;
      }

      blocks.push(
        <ul key={`tasks-${blocks.length}`} className="my-6 space-y-2.5 text-[16px] leading-8 text-[#526784]">
          {items.map((item, itemIndex) => (
            <li key={`${item.text}-${itemIndex}`} className="flex items-start gap-2.5">
              <span className={`mt-1.5 inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-[4px] border text-[10px] ${item.checked ? "border-[#2f6df6] bg-[#2f6df6] text-white" : "border-[#cbd5e3] bg-white"}`}>{item.checked ? "✓" : ""}</span>
              <span>{renderInline(item.text)}</span>
            </li>
          ))}
        </ul>,
      );
      continue;
    }

    if (/^[-*]\s+/.test(line)) {
      const items: string[] = [];

      while (index < lines.length && /^[-*]\s+/.test(lines[index].trim())) {
        items.push(lines[index].trim().replace(/^[-*]\s+/, ""));
        index += 1;
      }

      blocks.push(
        <ul key={`list-${blocks.length}`} className="my-6 list-outside list-disc space-y-2.5 pl-5 text-[16px] leading-8 text-[#526784] marker:text-[#2f6df6]">
          {items.map((item, itemIndex) => <li key={`${item}-${itemIndex}`}>{renderInline(item)}</li>)}
        </ul>,
      );
      continue;
    }

    if (/^\d+\.\s+/.test(line)) {
      const items: string[] = [];

      while (index < lines.length && /^\d+\.\s+/.test(lines[index].trim())) {
        items.push(lines[index].trim().replace(/^\d+\.\s+/, ""));
        index += 1;
      }

      blocks.push(
        <ol key={`ordered-${blocks.length}`} className="my-6 list-outside list-decimal space-y-3 pl-6 text-[16px] leading-8 text-[#526784] marker:font-semibold marker:text-[#2f6df6]">
          {items.map((item, itemIndex) => <li key={`${item}-${itemIndex}`}>{renderInline(item)}</li>)}
        </ol>,
      );
      continue;
    }

    const paragraphLines = [line];
    index += 1;

    while (index < lines.length && !isBlockStart(lines[index])) {
      paragraphLines.push(lines[index].trim());
      index += 1;
    }

    blocks.push(
      <p key={`paragraph-${blocks.length}`} className="mt-5 text-[16px] leading-8 text-[#526784] sm:text-[17px]">
        {renderInline(paragraphLines.join(" "))}
      </p>,
    );
    paragraphCount += 1;

    if (inlineContent && paragraphCount === inlineContentAfterParagraph) {
      blocks.push(<Fragment key="inline-content">{inlineContent}</Fragment>);
    }
  }

  return <div className={className}>{blocks}</div>;
}
