import type { UIMessage } from "ai";
import { memo, type ReactNode } from "react";

import { useOptionalAssistantContext } from "../../context";
import type { DisplayMessage } from "../../types";
import { Message } from "./message";

export interface MessageItemProps {
  displayMessage: DisplayMessage;
  isStreaming: boolean;
  liked?: boolean;
  disliked?: boolean;
  onLike?: (id: string, value: boolean) => void;
  onDislike?: (id: string, value: boolean, dislikeReason?: string, isUpdate?: boolean) => void;
  onRegenerate?: (id: string) => void;
  onEditMessage?: (messageId: string, newContent: string) => void;
  onSwitchBranch?: (messageId: string) => void;
  addToolApprovalResponse?: (args: { id: string; approved: boolean; reason?: string }) => void;
  extraActions?: ReactNode;
}

export const MessageItem = memo(
  function MessageItem({
    displayMessage,
    isStreaming,
    liked,
    disliked,
    onLike,
    onDislike,
    onRegenerate,
    onEditMessage,
    onSwitchBranch,
    addToolApprovalResponse,
    extraActions,
  }: MessageItemProps) {
    const { id, message, branchNumber, branchCount, branches, isLast } = displayMessage;
    const { onSpeak, showConversationContext, assistantAvatar } =
      useOptionalAssistantContext() ?? {};

    return (
      <Message
        message={message}
        liked={liked}
        disliked={disliked}
        isStreaming={isStreaming}
        branchNumber={branchNumber}
        branchCount={branchCount}
        branches={branches}
        isLast={isLast}
        onLikeChange={onLike ? (v) => onLike(id, v) : undefined}
        onDislikeChange={
          onDislike ? (v, reason, isUpdate) => onDislike(id, v, reason, isUpdate) : undefined
        }
        onRetry={onRegenerate ? () => onRegenerate(id) : undefined}
        onEditMessage={onEditMessage}
        onSwitchBranch={onSwitchBranch}
        addToolApprovalResponse={addToolApprovalResponse}
        extraActions={extraActions}
        onSpeak={onSpeak}
        showConversationContext={showConversationContext}
        assistantAvatar={assistantAvatar}
      />
    );
  },
  (prev, next) => {
    const {
      displayMessage: prevDm,
      isStreaming: prevStreaming,
      liked: prevLiked,
      disliked: prevDisliked,
    } = prev;
    const {
      displayMessage: nextDm,
      isStreaming: nextStreaming,
      liked: nextLiked,
      disliked: nextDisliked,
    } = next;

    if (
      prevDm.id !== nextDm.id ||
      prevDm.branchNumber !== nextDm.branchNumber ||
      prevDm.branchCount !== nextDm.branchCount ||
      prevDm.isLast !== nextDm.isLast ||
      prevStreaming !== nextStreaming ||
      prevLiked !== nextLiked ||
      prevDisliked !== nextDisliked
    )
      return false;

    const serializeParts = (parts: UIMessage["parts"]) =>
      parts
        ?.map((p) => {
          const type = p.type;
          if (type === "text" || type === "reasoning") {
            return `${type}:${(p as { text?: string }).text || ""}`;
          }
          if (type === "file") {
            const fp = p as { url?: string; filename?: string; mediaType?: string };
            return `file:${fp.url || ""}:${fp.filename || ""}:${fp.mediaType || ""}`;
          }
          if (type === "source-url") {
            const sp = p as { url?: string; title?: string };
            return `source-url:${sp.url || ""}:${sp.title || ""}`;
          }
          if (typeof type === "string" && type.startsWith("tool-")) {
            const tp = p as { toolCallId?: string; state?: string };
            return `${type}:${tp.toolCallId || ""}:${tp.state || ""}`;
          }
          if (type === "dynamic-tool") {
            const tp = p as { toolCallId?: string; state?: string; toolName?: string };
            return `dynamic-tool:${tp.toolName || ""}:${tp.toolCallId || ""}:${tp.state || ""}`;
          }
          if (type === "data-follow-up-suggestions") {
            const data = (p as { data?: unknown }).data;
            return `${type}:${Array.isArray(data) ? data.join("\n") : ""}`;
          }
          return String(type);
        })
        .join("|") || "";

    return serializeParts(prevDm.message.parts) === serializeParts(nextDm.message.parts);
  },
);
