import {
  Message,
  MessageContent,
  MessageResponse,
} from "@code/ui/components/ai-elements/message";
import {
  MobileChatBubble,
  MobileChatMessage,
} from "@code/ui/components/mobile-chat";

import {
  getMessageText,
  getReasoningText,
  isReasoningStreaming,
  isMessageStreaming,
} from "@/lib/chat/transforms";
import type {
  AssistantResponseState,
  ChatMessageProps,
} from "@/lib/chat/types";

import { AssistantIdentity } from "./assistant-identity";
import { MessageAttachments } from "./chat-attachments";

const ReasoningTrace = ({
  isStreaming,
  text,
}: {
  readonly isStreaming: boolean;
  readonly text: string;
}) => {
  if (!text) {
    return null;
  }
  return (
    <details
      className="mb-3 border-l-2 border-[#b9b5aa] pl-3 text-[#5f5d55]"
      open={isStreaming ? true : undefined}
    >
      <summary className="cursor-pointer select-none text-xs font-medium text-[#69675e]">
        {isStreaming ? "Thinking live" : "Thinking trace"}
      </summary>
      <MessageResponse
        className="chat-reasoning mt-2 min-w-0 text-xs leading-5"
        isAnimating={isStreaming}
      >
        {text}
      </MessageResponse>
    </details>
  );
};

const AssistantText = ({
  hasReasoning,
  isStreaming,
  text,
}: {
  readonly hasReasoning: boolean;
  readonly isStreaming: boolean;
  readonly text: string;
}) => {
  if (text) {
    return (
      <MessageResponse
        caret={isStreaming ? "block" : undefined}
        className="chat-markdown min-w-0"
        isAnimating={isStreaming}
      >
        {text}
      </MessageResponse>
    );
  }
  if (hasReasoning) {
    return null;
  }
  return (
    <div className="thinking-line" aria-label="Zopu is preparing a response">
      <span />
      <span />
      <span />
    </div>
  );
};

const assistantState = (
  isStreaming: boolean,
  reasoningStreaming: boolean,
  text: string
): AssistantResponseState | undefined => {
  if (reasoningStreaming && !text) {
    return "thinking";
  }
  return isStreaming ? "writing" : undefined;
};

export const ChatMessage = ({ message }: ChatMessageProps) => {
  const isUser = message.role === "user";
  const isStreaming = isMessageStreaming(message);
  const text = getMessageText(message);
  const reasoning = getReasoningText(message);
  const reasoningStreaming = isReasoningStreaming(message);
  const fileParts = message.parts.filter((part) => part.type === "file");

  if (message.parts.length === 0 && !isStreaming) {
    return null;
  }

  const sender = isUser ? "user" : "assistant";
  const content = isUser ? (
    text
  ) : (
    <AssistantText
      hasReasoning={Boolean(reasoning)}
      isStreaming={isStreaming}
      text={text}
    />
  );
  const identityState = assistantState(isStreaming, reasoningStreaming, text);

  return (
    <Message className="max-w-full gap-0" from={message.role}>
      <MessageContent className="w-full max-w-none gap-0 overflow-visible rounded-none bg-transparent p-0 group-[.is-user]:rounded-none group-[.is-user]:bg-transparent group-[.is-user]:p-0">
        <MobileChatMessage className="chat-message" sender={sender}>
          <div className={isUser ? "max-w-full" : "w-full min-w-0"}>
            {isUser ? null : <AssistantIdentity state={identityState} />}
            <MobileChatBubble
              className={isUser ? "whitespace-pre-wrap" : undefined}
              sender={sender}
            >
              <MessageAttachments parts={fileParts} />
              {isUser ? null : (
                <ReasoningTrace
                  isStreaming={reasoningStreaming}
                  text={reasoning}
                />
              )}
              {content}
            </MobileChatBubble>
          </div>
        </MobileChatMessage>
      </MessageContent>
    </Message>
  );
};
