"use client";
/**
 * ChatArea 消息列表区
 *
 * 组成（自上而下）：
 *   - AI 披露横幅
 *   - 日期分隔条
 *   - 消息气泡（AI 左 / 用户右）
 *   - AI 正在回复时的加载动画气泡
 *
 * 滚动行为：
 *   - 新消息到达时自动滚到底部
 *   - 用户向上滚动时不强制拉回（保持阅读上下文）
 */
import { useEffect, useLayoutEffect, useMemo, useRef } from "react";

import type { UiMessage } from "@/data/dto/chat";

import {
  buildChatRenderItems,
  createChatMessageKeyResolver,
  type ChatMessageKeyResolver,
} from "../chat-render-items";
import { AiDisclosureBanner } from "./ai-disclosure-banner";
import { DateHeader } from "./date-header";
import { LottieMessageBubble } from "./lottie-message-bubble";
import { MessageBubble } from "./message-bubble";
import styles from "./chat-area.module.css";

const CHAT_AUTO_SCROLL_BOTTOM_THRESHOLD = 96;

export interface ChatAreaProps {
  messages: readonly UiMessage[];
  isReplyingAI: boolean;
  isUnlockingMessage?: boolean;
  unlockingMessageId?: string | null;
  onUnlockPrivateMessage?: (messageId: string) => void;
  onUnlockVoiceMessage?: (messageId: string) => void;
  onOpenImage?: (messageId: string) => void;
}

export function ChatArea({
  messages,
  isReplyingAI,
  isUnlockingMessage,
  unlockingMessageId,
  onUnlockPrivateMessage,
  onUnlockVoiceMessage,
  onOpenImage,
}: ChatAreaProps) {
  const scrollRef = useRef<HTMLDivElement>(null);
  const prevLengthRef = useRef(messages.length);
  const initialScrollSettledRef = useRef(false);
  const wasNearBottomRef = useRef(true);
  const getMessageKey = useMemo(() => createChatMessageKeyResolver(), []);

  useLayoutEffect(() => {
    if (initialScrollSettledRef.current || messages.length === 0) return;
    const scrollNode = scrollRef.current;
    if (!scrollNode) return;

    initialScrollSettledRef.current = true;
    prevLengthRef.current = messages.length;
    scrollNode.scrollTop = scrollNode.scrollHeight;
    wasNearBottomRef.current = true;
  }, [messages.length]);

  // 新消息 → 滚到底部
  useEffect(() => {
    if (messages.length !== prevLengthRef.current) {
      const scrollNode = scrollRef.current;

      if (scrollNode && wasNearBottomRef.current) {
        scrollNode.scrollTo({
          top: scrollNode.scrollHeight,
          behavior: "smooth",
        });
      }
      prevLengthRef.current = messages.length;
    }
  }, [messages.length]);

  return (
    <main
      ref={scrollRef}
      className={styles.area}
      aria-label="Chat messages"
      onScroll={(event) => {
        wasNearBottomRef.current = isNearBottom(event.currentTarget);
      }}
    >
      <AiDisclosureBanner />

      {renderMessagesWithDateHeaders(
        messages,
        getMessageKey,
        isUnlockingMessage,
        unlockingMessageId,
        onUnlockPrivateMessage,
        onUnlockVoiceMessage,
        onOpenImage,
      )}

      {isReplyingAI && <LottieMessageBubble />}
    </main>
  );
}

function isNearBottom(scrollNode: HTMLElement): boolean {
  const distanceFromBottom =
    scrollNode.scrollHeight - scrollNode.scrollTop - scrollNode.clientHeight;
  return distanceFromBottom <= CHAT_AUTO_SCROLL_BOTTOM_THRESHOLD;
}

/** 渲染消息列表（按日期分组插入分隔条） */
function renderMessagesWithDateHeaders(
  messages: readonly UiMessage[],
  getMessageKey: ChatMessageKeyResolver,
  isUnlockingMessage?: boolean,
  unlockingMessageId?: string | null,
  onUnlockPrivateMessage?: (messageId: string) => void,
  onUnlockVoiceMessage?: (messageId: string) => void,
  onOpenImage?: (messageId: string) => void,
) {
  return buildChatRenderItems(messages, getMessageKey).map((item) =>
    item.type === "date" ? (
      <DateHeader key={item.key} date={item.date} />
    ) : (
      <MessageBubble
        key={item.key}
        messageId={item.message.id}
        content={item.message.content}
        imageUrl={item.message.imageUrl}
        imagePaywalled={item.message.imagePaywalled}
        audioUrl={item.message.audioUrl}
        isFromAI={item.message.isFromAI}
        locked={item.message.locked}
        lockReason={item.message.lockReason}
        lockedPrivate={item.message.lockedPrivate}
        privateMessageHint={item.message.privateMessageHint}
        isUnlockingMessage={
          isUnlockingMessage === true &&
          item.message.id === unlockingMessageId
        }
        onUnlockPrivateMessage={onUnlockPrivateMessage}
        onUnlockVoiceMessage={onUnlockVoiceMessage}
        onOpenImage={onOpenImage}
      />
    ),
  );
}
