"use client";

import { createCodePlugin } from "@streamdown/code";
import { defaultRehypePlugins, Streamdown } from "streamdown";
import type { Components, UrlTransform } from "streamdown";
import type { Root, RootContent } from "hast";

const codePlugin = createCodePlugin({
  themes: ["github-dark", "github-dark"],
});

const SAFE_ANCHOR = /^#[A-Za-z][A-Za-z0-9:._-]*$/;
const ABSOLUTE_HTTP_URL = /^https?:\/\/[^/?#\\]/i;
const FORBIDDEN_URL_CHARACTERS = /[\u0000-\u001F\u007F\\]/;
const DISALLOWED_ELEMENTS = ["img"] as const;

const transformMarkdownUrl = (url: string, key: string) => {
  if (key !== "href") return null;
  if (url !== url.trim()) return null;
  if (SAFE_ANCHOR.test(url)) return url;
  if (FORBIDDEN_URL_CHARACTERS.test(url)) return null;
  if (!ABSOLUTE_HTTP_URL.test(url)) return null;

  try {
    const parsed = new URL(url);
    const safeProtocol =
      parsed.protocol === "http:" || parsed.protocol === "https:";
    return safeProtocol && parsed.hostname ? url : null;
  } catch {
    return null;
  }
};

export const safeMarkdownUrl: UrlTransform = (url, key) =>
  transformMarkdownUrl(url, key);

const enforceSafeHrefs = () => (tree: Root) => {
  const visitNode = (node: Root | RootContent) => {
    if (node.type === "element" && "href" in node.properties) {
      const href = node.properties.href;
      const safeHref =
        typeof href === "string" ? transformMarkdownUrl(href, "href") : null;
      if (safeHref) node.properties.href = safeHref;
      else delete node.properties.href;
    }
    if ("children" in node) node.children.forEach(visitNode);
  };

  visitNode(tree);
};

const rehypePlugins = [
  defaultRehypePlugins.sanitize,
  enforceSafeHrefs,
  defaultRehypePlugins.harden,
];

const components: Components = {
  a: (componentProps) => {
    const { node, href, ...anchorProps } = componentProps;
    const sameDocument = href?.startsWith("#") ?? false;
    void node;
    return (
      <a
        {...anchorProps}
        href={href}
        rel={sameDocument ? undefined : "noopener noreferrer"}
        target={sameDocument ? undefined : "_blank"}
      />
    );
  },
  img: () => null,
};

type AssistantMarkdownProps = {
  content: string;
  isStreaming: boolean;
};

export function AssistantMarkdown({
  content,
  isStreaming,
}: AssistantMarkdownProps) {
  return (
    <Streamdown
      className="assistant-markdown min-w-0"
      components={components}
      controls={{
        code: { copy: true, download: false },
        mermaid: false,
        table: false,
      }}
      disallowedElements={DISALLOWED_ELEMENTS}
      isAnimating={isStreaming}
      linkSafety={{ enabled: false }}
      lineNumbers={false}
      mode={isStreaming ? "streaming" : "static"}
      parseIncompleteMarkdown
      plugins={{ code: codePlugin }}
      rehypePlugins={rehypePlugins}
      skipHtml
      translations={{
        copied: "Скопировано",
        copyCode: "Копировать код",
      }}
      urlTransform={safeMarkdownUrl}
    >
      {content}
    </Streamdown>
  );
}
