"use client";

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

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 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]">{token.slice(2, -2)}</strong>;
    }

    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 isBlockStart(value: string) {
  const line = value.trim();
  return (
    !line ||
    /^#{1,3}\s+/.test(line) ||
    /^[-*]\s+/.test(line) ||
    /^\d+\.\s+/.test(line) ||
    /^>\s?/.test(line) ||
    /^```/.test(line) ||
    /^---+$/.test(line) ||
    line.startsWith("|")
  );
}

export function MarkdownPreview({
  className = "",
  content,
}: {
  className?: string;
  content: string;
}) {
  const lines = content.replace(/\r\n/g, "\n").split("\n");
  const blocks: ReactNode[] = [];
  let index = 0;

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

    if (!line) {
      index += 1;
      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;
    }

    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,3})\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]"
            : "mt-10 text-[19px] font-semibold leading-8 tracking-[-0.04em] text-[#243555] sm:text-[21px]";
      const Tag = level === 1 ? "h1" : level === 2 ? "h2" : "h3";

      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+/.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 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 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>,
    );
  }

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