import {
  Block,
  BlockServices
} from "./chunk-MDAWYZBI.js";
import {
  IconCheck,
  IconCopy,
  IconThumbDown,
  IconThumbUp
} from "./chunk-XFJ6XMJZ.js";
import {
  IconButton
} from "./chunk-PYDVANWI.js";
import {
  typographyMixin,
  typographyTypes
} from "./chunk-UXT2H3FM.js";
import {
  colors
} from "./chunk-JF3P66JF.js";

// src/components/chat/chat-message/chat-message.tsx
import { useMemo } from "react";

// src/components/chat/hooks/copy-message-text.ts
function copyMessageText(message) {
  const parts = [];
  for (const block of message.blocks) {
    const service = BlockServices[block.type];
    if (!service) continue;
    if (!service.toClipboardText) continue;
    const text = service.toClipboardText(block);
    if (text) parts.push(text);
  }
  if (parts.length === 0) return message.fallbackText;
  return parts.join("\n\n");
}

// src/components/chat/chat-message-actions/chat-message-actions.tsx
import { useCallback as useCallback2 } from "react";

// src/components/chat/chat-context/chat-context.ts
import { createContext, useContext } from "react";
var ChatContext = createContext(null);
function useChatContext() {
  const context = useContext(ChatContext);
  if (!context) {
    throw new Error("useChatContext must be used within a Chat.Root component");
  }
  return context;
}

// src/components/chat/hooks/use-copy-to-clipboard.ts
import { useState, useCallback, useRef, useEffect } from "react";

// src/utils/clipboard.ts
function copyToClipboard(text, options) {
  navigator.clipboard.writeText(text).then(
    () => options?.onSuccess?.(),
    (error) => options?.onFailure?.(error)
  );
}

// src/components/chat/hooks/use-copy-to-clipboard.ts
var RESET_DELAY_MS = 2e3;
function useCopyToClipboard() {
  const [isCopied, setIsCopied] = useState(false);
  const timeoutRef = useRef(null);
  useEffect(() => {
    return () => {
      if (timeoutRef.current) clearTimeout(timeoutRef.current);
    };
  }, []);
  const copy = useCallback((text) => {
    copyToClipboard(text, {
      onSuccess: () => {
        setIsCopied(true);
        if (timeoutRef.current) clearTimeout(timeoutRef.current);
        timeoutRef.current = setTimeout(() => {
          setIsCopied(false);
          timeoutRef.current = null;
        }, RESET_DELAY_MS);
      }
    });
  }, []);
  return { isCopied, copy };
}

// src/components/chat/constants.ts
var MESSAGE_ROLE = {
  USER: "user",
  ASSISTANT: "assistant"
};

// src/components/chat/chat-message-actions/chat-message-actions-styles.ts
import styled from "styled-components";
var FADE_DURATION_MS = 150;
var ANIMATE_DURATION_MS = 200;
var ActionsContainer = styled.div`
  display: flex;
  opacity: ${({ $role }) => $role === MESSAGE_ROLE.ASSISTANT ? 1 : 0};
  pointer-events: ${({ $role }) => $role === MESSAGE_ROLE.ASSISTANT ? "auto" : "none"};
  transition: opacity ${FADE_DURATION_MS}ms ease;
`;
var AnimatedAction = styled.div`
  display: flex;
  overflow: hidden;
  max-width: ${({ $visible }) => $visible ? "40px" : "0"};
  opacity: ${({ $visible }) => $visible ? 1 : 0};
  transition: max-width ${ANIMATE_DURATION_MS}ms ease, opacity ${ANIMATE_DURATION_MS}ms ease;
`;

// src/components/chat/chat-message-actions/chat-message-actions.tsx
import { jsx, jsxs } from "react/jsx-runtime";
function ChatMessageActions({ className, messageId, content, role, isHelpful }) {
  const { onCopyMessage, onThumbUpClick, onThumbDownClick } = useChatContext();
  const { isCopied, copy } = useCopyToClipboard();
  const handleCopy = useCallback2(() => {
    copy(content);
    onCopyMessage?.(messageId);
  }, [content, messageId, copy, onCopyMessage]);
  const handleThumbUp = useCallback2(() => {
    onThumbUpClick?.(messageId, isHelpful === true ? null : true);
  }, [messageId, isHelpful, onThumbUpClick]);
  const handleThumbDown = useCallback2(() => {
    onThumbDownClick?.(messageId, isHelpful === false ? null : false);
  }, [messageId, isHelpful, onThumbDownClick]);
  const isAssistant = role === MESSAGE_ROLE.ASSISTANT;
  const hasFeedback = isAssistant && (onThumbUpClick || onThumbDownClick);
  return /* @__PURE__ */ jsxs(ActionsContainer, { $role: role, className, children: [
    /* @__PURE__ */ jsx(
      IconButton,
      {
        icon: isCopied ? IconCheck : IconCopy,
        onClick: handleCopy,
        "aria-label": isCopied ? "Copied" : "Copy message"
      }
    ),
    hasFeedback && /* @__PURE__ */ jsx(AnimatedAction, { $visible: isHelpful !== false, children: /* @__PURE__ */ jsx(
      IconButton,
      {
        icon: IconThumbUp,
        onClick: handleThumbUp,
        isSelected: isHelpful === true,
        "aria-label": "Good response"
      }
    ) }),
    hasFeedback && /* @__PURE__ */ jsx(AnimatedAction, { $visible: isHelpful !== true, children: /* @__PURE__ */ jsx(
      IconButton,
      {
        icon: IconThumbDown,
        onClick: handleThumbDown,
        isSelected: isHelpful === false,
        "aria-label": "Bad response"
      }
    ) })
  ] });
}

// src/components/chat/chat-message/chat-message-styles.ts
import styled2 from "styled-components";
var MessageRow = styled2.div`
  display: flex;
  justify-content: ${({ $role }) => $role === MESSAGE_ROLE.USER ? "flex-end" : "flex-start"};

  &:hover ${ActionsContainer} {
    opacity: 1;
    pointer-events: auto;
  }
`;
var MessageContainer = styled2.div`
  display: flex;
  flex-direction: column;
  align-items: ${({ $role }) => $role === MESSAGE_ROLE.USER ? "flex-end" : "flex-start"};
  max-width: 90%;
  width: ${({ $role }) => $role === MESSAGE_ROLE.USER ? "auto" : "100%"};
  gap: 12px;
`;
var MessageBubble = styled2.div`
  ${typographyMixin(typographyTypes.GEIST_BODY_S_REGULAR)};
  color: ${colors["brown-100"]};
  background: ${({ $role }) => $role === MESSAGE_ROLE.USER ? colors.white : "transparent"};
  padding: ${({ $role }) => $role === MESSAGE_ROLE.USER ? "12px 16px" : "0"};
  border-radius: ${({ $role }) => $role === MESSAGE_ROLE.USER ? "16px" : "0"};
  max-width: 100%;
  width: 100%;
  min-width: 0;
  /* Vertical rhythm between consecutive blocks — renderer-owned, not agent-emitted.
   * Industry standard (Claude, ChatGPT, Vercel AI Elements): the chat renderer applies
   * spacing via CSS; agents emit semantic blocks only. Value matches the MessageContainer
   * gap. TODO: replace 12px with a clay spacing token when a spacing scale is added. */
  display: flex;
  flex-direction: column;
  gap: 12px;
`;

// src/components/chat/chat-message/chat-message.tsx
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
function ChatMessage({ message }) {
  const clipboardText = useMemo(() => copyMessageText(message), [message]);
  return /* @__PURE__ */ jsx2(MessageRow, { $role: message.role, role: "article", "aria-label": `${message.role} message`, children: /* @__PURE__ */ jsxs2(MessageContainer, { $role: message.role, children: [
    /* @__PURE__ */ jsx2(MessageBubble, { $role: message.role, "data-testid": "message-bubble", children: message.blocks.map((block, index) => /* @__PURE__ */ jsx2(Block, { block }, index)) }),
    /* @__PURE__ */ jsx2(
      ChatMessageActions,
      {
        messageId: message.id,
        content: clipboardText,
        role: message.role,
        isHelpful: message.isHelpful
      }
    )
  ] }) });
}

export {
  copyMessageText,
  ChatContext,
  useChatContext,
  useCopyToClipboard,
  MESSAGE_ROLE,
  ChatMessage
};
//# sourceMappingURL=chunk-3THOTQO3.js.map