import type { ChatMessage } from "@qjclaw/shared-types"
import type { ReactNode, RefObject, UIEvent } from "react"
import { getTraceLineClassName, getTraceLineLabels } from "./messageTraceDisplay"
import type { MessageTraceState } from "./useMessageTraces"

type ViewMode = "chat" | "experts" | "plugins" | "settings" | "knowledge"
type MessageReaction = "up" | "down"
export type ExpertKey = "xiaohongshu" | "douyin" | "browser" | "general"

export type MessageListMessage = ChatMessage & {
  streamState?: "streaming" | "error"
  statusLabel?: string
  statusDetail?: string
}

interface VideoStatusCardContent {
  title: string
  meta?: string
  hint?: string
}

interface MessageListLabels {
  thinking: string
  hideTrace: string
  traceCollapsed: string
}

interface MessageListProps {
  messages: MessageListMessage[]
  viewMode: ViewMode
  showBindEntry: boolean
  showEmptyState: boolean
  emptyState: ReactNode
  messageListRef: RefObject<HTMLDivElement | null>
  messageTraces: Record<string, MessageTraceState>
  messageReactions: Record<string, MessageReaction | undefined>
  copiedToken: string
  sending: boolean
  activeExpertKey: ExpertKey
  labels: MessageListLabels
  copyIcon: ReactNode
  copiedIcon: ReactNode
  regenerateIcon: ReactNode
  renderThumbIcon: (direction: MessageReaction) => ReactNode
  renderMarkdownContent: (
    content: string,
    options: {
      messageId: string
      copiedToken: string
      onCopy: (token: string, text: string) => void | Promise<void>
    }
  ) => ReactNode[]
  buildDouyinVideoStatusCard: (message: MessageListMessage, expertKey: ExpertKey) => VideoStatusCardContent | null
  formatMessageTimestamp: (value: string) => string
  onScroll: (event: UIEvent<HTMLDivElement>) => void
  onCopyText: (token: string, text: string) => void | Promise<void>
  onTraceExpandedChange: (messageId: string, expanded: boolean) => void
  onRegenerateAssistantMessage: (messageId: string) => void | Promise<void>
  onToggleMessageReaction: (messageId: string, reaction: MessageReaction) => void
}

export function MessageList({
  messages,
  viewMode,
  showBindEntry,
  showEmptyState,
  emptyState,
  messageListRef,
  messageTraces,
  messageReactions,
  copiedToken,
  sending,
  activeExpertKey,
  labels,
  copyIcon,
  copiedIcon,
  regenerateIcon,
  renderThumbIcon,
  renderMarkdownContent,
  buildDouyinVideoStatusCard,
  formatMessageTimestamp,
  onScroll,
  onCopyText,
  onTraceExpandedChange,
  onRegenerateAssistantMessage,
  onToggleMessageReaction
}: MessageListProps) {
  return (
    <div ref={messageListRef} onScroll={onScroll} className={"message-list chat-scroll-smooth" + (viewMode === "chat" ? " message-list-home" : "")}>
      {messages.map((message) => {
        const showThinking = message.role === "assistant" && message.streamState === "streaming" && !message.content.trim()
        const videoStatusCard = showThinking ? buildDouyinVideoStatusCard(message, activeExpertKey) : null
        const messageTrace = message.role === "assistant" ? messageTraces[message.id] : undefined
        const hasTrace = Boolean(messageTrace?.items.length)
        const isTraceExpanded = Boolean(messageTrace?.expanded)
        const canCopyMessage = Boolean(message.content.trim())
        const copyToken = `message:${message.id}`
        const reaction = messageReactions[message.id]
        void reaction

        return (
          <article key={message.id} className={"message-card group " + message.role + (message.streamState ? " " + message.streamState : "")}>
            <div className={"message-bubble" + (message.role === "assistant" ? " message-bubble-assistant" : " message-bubble-user")}>
              {showThinking ? (
                videoStatusCard ? (
                  <div className="generation-status-card" aria-live="polite">
                    <div className="generation-status-leading">
                      <span className="thinking-spinner generation-status-spinner" aria-hidden="true" />
                    </div>
                    <div className="generation-status-body">
                      <span className="generation-status-kicker">抖音专家执行中</span>
                      <strong className="generation-status-title">{videoStatusCard.title}</strong>
                      {videoStatusCard.meta ? <span className="generation-status-meta">{videoStatusCard.meta}</span> : null}
                      {videoStatusCard.hint ? <span className="generation-status-hint">{videoStatusCard.hint}</span> : null}
                      <span className="generation-status-progress" aria-hidden="true" />
                    </div>
                  </div>
                ) : (
                  <div className="thinking-indicator" aria-live="polite">
                    <span className="thinking-spinner" aria-hidden="true" />
                    <span className="thinking-label">{message.statusLabel ?? labels.thinking}</span>
                    {message.statusDetail ? <span className="thinking-detail">{message.statusDetail}</span> : null}
                  </div>
                )
              ) : message.content ? (
                message.role === "assistant" ? (
                  <div className="markdown-body">
                    {renderMarkdownContent(message.content, {
                      messageId: message.id,
                      copiedToken,
                      onCopy: onCopyText
                    })}
                    {message.streamState === "streaming" ? <span className="message-cursor" aria-hidden="true" /> : null}
                  </div>
                ) : (
                  <p className="message-plain-text">
                    {message.content}
                    {message.streamState === "streaming" ? <span className="message-cursor" aria-hidden="true" /> : null}
                  </p>
                )
              ) : null}
              {hasTrace ? (
                <div className="message-trace">
                  <button type="button" className="trace-inline-toggle" onClick={() => onTraceExpandedChange(message.id, !isTraceExpanded)}>
                    {isTraceExpanded ? labels.hideTrace : labels.traceCollapsed}
                  </button>
                  {isTraceExpanded ? (
                    <div className="message-trace-content">
                      {messageTrace?.items.map((item) => {
                        const traceLabels = getTraceLineLabels(item)
                        return (
                          <p key={item.id} className={getTraceLineClassName(item.tone)}>
                            <span className="message-trace-time">{traceLabels.time}</span>
                            <span className="message-trace-text">{traceLabels.label}</span>
                            {traceLabels.detail ? <span className="message-trace-detail">{traceLabels.detail}</span> : null}
                          </p>
                        )
                      })}
                    </div>
                  ) : null}
                </div>
              ) : null}
            </div>
            <span className="message-timestamp" aria-hidden="true">{formatMessageTimestamp(message.createdAt)}</span>
            {message.role === "assistant" && canCopyMessage ? (
              <div className="message-card-actions">
                <button
                  type="button"
                  className={"message-action-icon" + (copiedToken === copyToken ? " copied" : "")}
                  onClick={() => void onCopyText(copyToken, message.content)}
                  aria-label="复制消息"
                  title="复制消息"
                >
                  {copiedToken === copyToken ? copiedIcon : copyIcon}
                </button>
                {message.role === "assistant" ? (
                  <>
                    <button
                      type="button"
                      className="hidden"
                      onClick={() => void onRegenerateAssistantMessage(message.id)}
                      disabled={sending}
                      aria-label="重新生成"
                      title="重新生成"
                    >
                      {regenerateIcon}
                    </button>
                    <button
                      type="button"
                      className="hidden"
                      onClick={() => onToggleMessageReaction(message.id, "up")}
                      aria-label="赞"
                      title="赞"
                    >
                      {renderThumbIcon("up")}
                    </button>
                    <button
                      type="button"
                      className="hidden"
                      onClick={() => onToggleMessageReaction(message.id, "down")}
                      aria-label="踩"
                      title="踩"
                    >
                      {renderThumbIcon("down")}
                    </button>
                  </>
                ) : null}
              </div>
            ) : null}
          </article>
        )
      })}
      {!messages.length && !showBindEntry && showEmptyState ? emptyState : null}
    </div>
  )
}
