import { forwardRef, useState, useEffect, useCallback } from 'react';
import { useTheme, css } from '@emotion/react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { useI18n } from '@timeui/core';
import { jsx, jsxs } from '@emotion/react/jsx-runtime';

var Link = (props) => {
  const { href, children, ...rest } = props;
  const isExternal = typeof href === "string" && /^https?:\/\//.test(href);
  return /* @__PURE__ */ jsx(
    "a",
    {
      href,
      target: isExternal ? "_blank" : void 0,
      rel: isExternal ? "noreferrer noopener" : void 0,
      ...rest,
      children
    }
  );
};
function extractLanguage(className) {
  if (!className) return void 0;
  const match = /language-([\w+-]+)/.exec(className);
  return match?.[1];
}
function toPlainText(children) {
  if (children == null || children === false) return "";
  if (typeof children === "string") return children;
  if (typeof children === "number") return String(children);
  if (Array.isArray(children)) return children.map(toPlainText).join("");
  if (typeof children === "object" && "props" in children) {
    const el = children;
    return toPlainText(el.props?.children);
  }
  return "";
}
function CodeBlockInline({ code, language }) {
  const theme = useTheme();
  const i18n = useI18n();
  const [highlightedHtml, setHighlightedHtml] = useState(null);
  const [copied, setCopied] = useState(false);
  useEffect(() => {
    if (!language) {
      setHighlightedHtml(null);
      return;
    }
    let cancelled = false;
    (async () => {
      try {
        const shiki = await import('shiki');
        const highlighter = await shiki.getSingletonHighlighter({
          themes: ["github-light", "github-dark"],
          langs: [language]
        });
        const loaded = highlighter.getLoadedLanguages();
        if (!loaded.includes(language)) {
          await highlighter.loadLanguage(language);
        }
        if (cancelled) return;
        const html = highlighter.codeToHtml(code, {
          lang: language,
          themes: { light: "github-light", dark: "github-dark" },
          defaultColor: theme.mode === "dark" ? "dark" : "light"
        });
        if (!cancelled) setHighlightedHtml(html);
      } catch (err) {
        if (process.env.NODE_ENV !== "production") {
          console.warn(
            "[TimeUI] ChatMarkdown: syntax highlighting unavailable \u2014 falling back to plain text.",
            err
          );
        }
        if (!cancelled) setHighlightedHtml(null);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [code, language, theme.mode]);
  const handleCopy = useCallback(async () => {
    if (typeof navigator === "undefined" || !navigator.clipboard) return;
    try {
      await navigator.clipboard.writeText(code);
      setCopied(true);
      window.setTimeout(() => setCopied(false), 2e3);
    } catch {
    }
  }, [code]);
  const border = theme.colors.border.subtle;
  const bg = theme.colors.bg.sunken ?? theme.colors.bg.muted;
  const wrapperCss = css`
    position: relative;
    margin: 0 0 0.5em;
    border-radius: 8px;
    border: 1px solid ${border};
    background: ${bg};
    overflow: hidden;
    font-size: 0.86em;
    line-height: 1.55;

    /* shiki 注入的 <pre class="shiki"> 使用自己的配色，这里只做容器 padding/滚动统一 */
    pre {
      margin: 0;
      padding: 10px 44px 10px 12px;
      background: transparent;
      overflow-x: auto;
      font-family: ${theme.typography.fontFamily.mono};
    }
    .shiki {
      background: transparent !important;
      font-family: ${theme.typography.fontFamily.mono} !important;
    }
    code {
      font-family: ${theme.typography.fontFamily.mono};
      background: transparent;
      padding: 0;
      border-radius: 0;
      font-size: inherit;
      white-space: pre;
      word-break: normal;
    }

    /* 悬停容器时显现复制按钮；键盘 focus / copied 状态也会显现（见 button 规则） */
    &:hover [data-timeui-copy-btn],
    &:focus-within [data-timeui-copy-btn] {
      opacity: 1;
    }
  `;
  const copyBtnCss = css`
    position: absolute;
    top: 6px;
    right: 6px;
    padding: 3px 8px;
    font-family: ${theme.typography.fontFamily.mono};
    font-size: 11px;
    letter-spacing: 0.02em;
    color: ${theme.colors.text.muted};
    background: ${theme.colors.bg.surface};
    border: 1px solid ${border};
    border-radius: 6px;
    cursor: pointer;
    opacity: 0;
    transition:
      opacity 150ms,
      background 150ms,
      color 150ms,
      border-color 150ms;
    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
    /* 保持 a11y：键盘 focus 与"已复制"状态始终可见。 */
    &:focus-visible,
    &[data-copied] {
      opacity: 1;
    }
    &:hover,
    &:focus-visible {
      background: ${theme.colors.bg.muted};
      color: ${theme.colors.text.primary};
      outline: none;
    }
    &:focus-visible {
      border-color: ${theme.colors.focus};
    }
  `;
  return /* @__PURE__ */ jsxs("div", { css: wrapperCss, children: [
    highlightedHtml ? /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: highlightedHtml } }) : /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { className: language ? `language-${language}` : void 0, children: code }) }),
    /* @__PURE__ */ jsx(
      "button",
      {
        type: "button",
        onClick: handleCopy,
        "aria-label": i18n.codeBlock.copyLabel,
        "data-copied": copied || void 0,
        "data-timeui-copy-btn": "",
        css: copyBtnCss,
        children: copied ? i18n.codeBlock.copied : i18n.codeBlock.copy
      }
    )
  ] });
}
var PreRenderer = (props) => {
  const { children } = props;
  const onlyChild = Array.isArray(children) ? children[0] : children;
  if (onlyChild && typeof onlyChild === "object" && "props" in onlyChild) {
    const codeEl = onlyChild;
    const language = extractLanguage(codeEl.props?.className);
    const codeText = toPlainText(codeEl.props?.children).replace(/\n$/, "");
    return /* @__PURE__ */ jsx(CodeBlockInline, { code: codeText, language });
  }
  return /* @__PURE__ */ jsx("pre", { ...props });
};
var ChatMarkdown = forwardRef(
  function ChatMarkdown2(props, forwardedRef) {
    const { children, className, style, components: overrides } = props;
    const theme = useTheme();
    const rootCss = css`
      font-size: inherit;
      line-height: ${theme.components.chat.contentLineHeight};
      color: inherit;
      word-break: break-word;

      & > :first-of-type {
        margin-top: 0;
      }
      & > :last-child {
        margin-bottom: 0;
      }

      p {
        margin: 0 0 0.5em;
      }
      p:last-child {
        margin-bottom: 0;
      }

      strong {
        font-weight: 600;
      }
      em {
        font-style: italic;
      }

      a {
        color: ${theme.colors.text.link ?? theme.colors.primary?.[500] ?? "inherit"};
        text-decoration: underline;
        text-underline-offset: 2px;
        text-decoration-thickness: 1px;
        &:hover {
          text-decoration-thickness: 2px;
        }
      }

      ul,
      ol {
        margin: 0.25em 0 0.4em;
        padding-left: 1.25em;
      }
      /* LLM 经常在段落和列表之间多换一行；把 p→ul/ol 的过渡收紧。 */
      p + ul,
      p + ol {
        margin-top: -0.15em;
      }
      /* loose markdown 偶尔把每个 bullet 拆成独立 <ul>；让相邻列表视觉合并。 */
      ul + ul,
      ol + ol,
      ul + ol,
      ol + ul {
        margin-top: -0.3em;
      }
      li {
        margin: 0;
      }
      li + li {
        margin-top: 0.15em;
      }
      /* react-markdown 在 loose list 里会把 <li> 内容包进 <p>；消掉它的外 margin。 */
      li > p {
        margin: 0;
      }
      li > p + p {
        margin-top: 0.3em;
      }
      ul ul,
      ul ol,
      ol ul,
      ol ol {
        margin: 0.1em 0 0;
      }

      blockquote {
        margin: 0 0 0.5em;
        padding: 4px 12px;
        border-left: 3px solid ${theme.colors.border.default};
        color: ${theme.colors.text.secondary};
        background: ${theme.colors.bg.sunken ?? theme.colors.bg.muted};
        border-radius: 0 6px 6px 0;
      }

      hr {
        border: 0;
        border-top: 1px solid ${theme.colors.border.subtle};
        margin: 0.7em 0;
      }

      h1,
      h2,
      h3,
      h4,
      h5,
      h6 {
        margin: 0.6em 0 0.25em;
        line-height: 1.3;
        font-weight: 600;
      }
      /* 第一个标题不要再吃额外上 margin（已被 :first-of-type 处理，但保险）。 */
      :is(h1, h2, h3, h4, h5, h6):first-of-type {
        margin-top: 0;
      }
      h1 {
        font-size: 1.25em;
      }
      h2 {
        font-size: 1.15em;
      }
      h3 {
        font-size: 1.05em;
      }
      h4,
      h5,
      h6 {
        font-size: 1em;
      }

      /* 行内 code 保持原有视觉；fenced code block 由 CodeBlockInline 接管，
         所以这里的 pre 规则仅对 caller 透过 components prop 覆盖后的回落路径生效。 */
      code {
        font-family: ${theme.typography.fontFamily.mono};
        font-size: 0.88em;
        background: ${theme.colors.bg.sunken ?? theme.colors.bg.muted};
        padding: 1px 5px;
        border-radius: 4px;
        word-break: break-all;
      }

      pre {
        margin: 0 0 0.5em;
        padding: 10px 12px;
        background: ${theme.colors.bg.sunken ?? theme.colors.bg.muted};
        border: 1px solid ${theme.colors.border.subtle};
        border-radius: 8px;
        overflow-x: auto;
        font-size: 0.86em;
        line-height: 1.55;
      }
      pre code {
        background: transparent;
        padding: 0;
        border-radius: 0;
        font-size: inherit;
        word-break: normal;
        white-space: pre;
      }

      table {
        margin: 0 0 0.5em;
        border-collapse: collapse;
        border: 1px solid ${theme.colors.border.subtle};
        border-radius: 6px;
        overflow: hidden;
        font-size: 0.95em;
      }
      th,
      td {
        padding: 6px 10px;
        border-bottom: 1px solid ${theme.colors.border.subtle};
        text-align: left;
        vertical-align: top;
      }
      th {
        font-weight: 600;
        background: ${theme.colors.bg.muted};
      }
      tr:last-child td {
        border-bottom: 0;
      }

      img {
        max-width: 100%;
        height: auto;
        border-radius: 6px;
      }
    `;
    const baseComponents = { a: Link, pre: PreRenderer };
    const merged = { ...baseComponents, ...overrides ?? {} };
    return /* @__PURE__ */ jsx("div", { ref: forwardedRef, className, style, css: rootCss, children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], components: merged, children }) });
  }
);
ChatMarkdown.displayName = "ChatMarkdown";

export { ChatMarkdown };
//# sourceMappingURL=chat-markdown.js.map
//# sourceMappingURL=chat-markdown.js.map