"use client";

import React, { useState } from "react";
import { Check, Copy } from "lucide-react";
import ReactMarkdown from "react-markdown";
import type { PluggableList } from "unified";
import remarkGfm from "remark-gfm";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
import { extractMarkdownHeadings } from "@/lib/markdown-headings";
import { cn } from "@/lib/utils";

type MarkdownSize = "sm" | "base" | "lg";

type MarkdownProps = {
  content?: string;
  allowHtml?: boolean;
  className?: string;
  dir?: "rtl" | "ltr";
  justify?: boolean;
  size?: MarkdownSize;
};

function CodeBlock({
  className,
  children,
}: {
  className?: string;
  children: React.ReactNode;
}) {
  const [copied, setCopied] = useState(false);
  const language = /language-([\w-]+)/.exec(className || "")?.[1] || "text";
  const code = String(children).replace(/\n$/, "");

  const copyCode = async () => {
    if (!navigator.clipboard) return;
    await navigator.clipboard.writeText(code);
    setCopied(true);
    window.setTimeout(() => setCopied(false), 1600);
  };

  return (
    <div
      dir="ltr"
      className="my-5 overflow-hidden rounded-2xl border border-slate-700/70 bg-[#0f172a] text-left shadow-xl shadow-slate-950/10"
    >
      <div className="flex items-center justify-between border-b border-white/10 bg-white/5 px-4 py-2 text-xs text-slate-300">
        <span className="font-mono uppercase tracking-wide">{language}</span>
        <button
          type="button"
          onClick={copyCode}
          className="inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-slate-300 transition hover:bg-white/10 hover:text-white"
        >
          {copied ? <Check className="h-3.5 w-3.5" /> : <Copy className="h-3.5 w-3.5" />}
          {copied ? "Copied" : "Copy"}
        </button>
      </div>
      <SyntaxHighlighter
        language={language}
        style={oneDark}
        PreTag="div"
        customStyle={{
          margin: 0,
          background: "transparent",
          direction: "ltr",
          padding: "1rem",
        }}
        codeTagProps={{
          dir: "ltr",
          style: {
            direction: "ltr",
            textAlign: "left",
            fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
          },
        }}
      >
        {code}
      </SyntaxHighlighter>
    </div>
  );
}

export default function Markdown({
  content = "",
  allowHtml = false,
  className = "",
  dir = "rtl",
  justify = false,
  size = "sm",
}: MarkdownProps) {
  const rehypePlugins: PluggableList | undefined = allowHtml ? [rehypeRaw, rehypeSanitize] : undefined;
  const headings = extractMarkdownHeadings(content);
  let headingIndex = 0;

  const baseSizeClass =
    size === "sm" ? "text-sm" : size === "lg" ? "text-lg" : "text-base";

  const hScale =
    size === "sm"
      ? { h1: "text-xl", h2: "text-lg", h3: "text-base", h4: "text-base" }
      : size === "base"
      ? { h1: "text-3xl", h2: "text-2xl", h3: "text-xl", h4: "text-lg" }
      : { h1: "text-4xl", h2: "text-3xl", h3: "text-2xl", h4: "text-xl" };

  const justifyStyle: React.CSSProperties | undefined = justify
    ? { textAlign: "justify", textJustify: "inter-word" }
    : undefined;

  const nextHeadingId = (level: 1 | 2 | 3) => {
    while (headingIndex < headings.length) {
      const heading = headings[headingIndex];
      headingIndex += 1;
      if (heading.level === level) return heading.id;
    }
    return undefined;
  };

  return (
    <div
      dir={dir}
      className={cn("markdown-body break-words text-right leading-8", baseSizeClass, className)}
      style={justifyStyle}
    >
      <ReactMarkdown
        remarkPlugins={[remarkGfm]}
        rehypePlugins={rehypePlugins}
        components={{
          h1: (p) => <h1 id={nextHeadingId(1)} className={cn("scroll-mt-28 pt-2 font-bold", hScale.h1)} {...p} />,
          h2: (p) => <h2 id={nextHeadingId(2)} className={cn("scroll-mt-28 pt-2 font-bold", hScale.h2)} {...p} />,
          h3: (p) => <h3 id={nextHeadingId(3)} className={cn("scroll-mt-28 pt-2 font-semibold", hScale.h3)} {...p} />,
          h4: (p) => <h4 className={cn("mt-4 font-semibold", hScale.h4)} {...p} />,
          p: (p) => <p className="my-4" {...p} />,
          a: (p) => <a className="break-all underline decoration-primary hover:opacity-90" target="_blank" rel="noopener noreferrer" {...p} />,
          ul: (p) => <ul className="my-4 list-disc space-y-1.5 pe-0 ps-6" {...p} />,
          ol: (p) => <ol className="my-4 list-decimal space-y-1.5 pe-0 ps-6" {...p} />,
          li: (p) => <li className="[&>ol]:my-1.5 [&>ul]:my-1.5" {...p} />,
          hr: (p) => <hr className="my-6 border-muted" {...p} />,
          blockquote: (p) => (
            <blockquote className="my-4 rounded-2xl border-r-4 border-primary bg-muted/40 py-3 pr-4 italic text-muted-foreground" {...p} />
          ),
          code: ({ className, children, node, ...p }) => {
            const isInline =
              node?.tagName === "code" &&
              !/language-/.test(className || "") &&
              !String(children).includes("\n");

            if (isInline) {
              return (
                <code dir="ltr" className="rounded bg-muted px-1.5 py-0.5 text-[0.9em]" {...p}>
                  {children}
                </code>
              );
            }

            return <CodeBlock className={className}>{children}</CodeBlock>;
          },
          pre: ({ children }) => <>{children}</>,
          table: (p) => (
            <div className="my-4 overflow-x-auto">
              <table className="w-full border-collapse" {...p} />
            </div>
          ),
          th: (p) => <th className="border-b p-2 text-right font-semibold" {...p} />,
          td: (p) => <td className="border-b p-2 align-top" {...p} />,
        }}
      >
        {content}
      </ReactMarkdown>
    </div>
  );
}
