"use client";

import { ChatMessageRow } from "@/components/chat-message-row";
import {
  ChatMessageActions,
  toggleChatMessageFeedback,
  type ChatMessageFeedback,
} from "@/components/chat-message-actions";
import { ConversationFollowUps } from "@/components/conversation-follow-ups";
import { isGeneralDailyFortuneQuestion } from "@/lib/consultation-entrypoint";
import { deriveConsultationFollowUps } from "@/lib/consultation-follow-ups";
import type { ConsultationDomain } from "@/lib/consultation-domain-registry";
import type { AgentActivityView, ChatMessage, ChatMessageView } from "@/lib/chat-message-view";
import {
  chatMessageViews,
  latestAssistantView,
  settledChatMessageViews,
} from "@/lib/chat-message-view";
import type { PublicThinkingSection } from "@/lib/consultation-thinking-plan";
import type { ConsultationTimelineRow } from "@/lib/consultation-run-timeline";
import {
  noteLatestEntryMount,
  noteSettledListRender,
  noteSettledRowRender,
  noteStreamingRowRender,
  noteUnsplitListRender,
} from "@/lib/home-streaming-render-probe";
import { memo, useEffect, type MutableRefObject } from "react";

export type ChatTranscriptActions = Readonly<{
  onFeedback: (feedbackKey: string, requested: ChatMessageFeedback) => void;
  onCopy: (feedbackKey: string, text: string) => void;
  onRegenerate: (renderKey: string) => void;
  onFollowUp: (question: string) => void;
}>;

export type ChatTranscriptProps = Readonly<{
  messages: readonly ChatMessage[];
  loading: boolean;
  streamingText: string;
  streamingActivity?: AgentActivityView;
  streamingThinking?: string;
  streamingSections?: readonly PublicThinkingSection[];
  streamingTimeline?: readonly ConsultationTimelineRow[];
  sessionId: string;
  sessionType: "consultation" | "birth_time_rectification";
  theme?: ConsultationDomain;
  messageFeedback: Readonly<Record<string, ChatMessageFeedback>>;
  copiedMessageKey: string | null;
  cancellationPending: boolean;
  productEntrypointsDisabled: boolean;
  actionsRef: MutableRefObject<ChatTranscriptActions>;
}>;

type MessageEntryProps = Readonly<{
  message: ChatMessageView;
  views: readonly ChatMessageView[];
  index: number;
  sessionId: string;
  sessionType: "consultation" | "birth_time_rectification";
  theme?: ConsultationDomain;
  messageFeedback: Readonly<Record<string, ChatMessageFeedback>>;
  copiedMessageKey: string | null;
  loading: boolean;
  cancellationPending: boolean;
  productEntrypointsDisabled: boolean;
  actionsRef: MutableRefObject<ChatTranscriptActions>;
}>;

/**
 * One transcript row. The same component renders history rows, the row that is
 * still streaming and the row that just settled: actions and follow-ups appear
 * once the view is settled, nothing remounts when it does.
 */
function MessageEntry({
  message,
  views,
  index,
  sessionId,
  sessionType,
  theme,
  messageFeedback,
  copiedMessageKey,
  loading,
  cancellationPending,
  productEntrypointsDisabled,
  actionsRef,
}: MessageEntryProps) {
  const showActions = message.role === "assistant"
    && message.state === "settled"
    && Boolean(message.text);
  const feedbackKey = `${sessionId}:${message.renderKey}`;
  const latestRegeneratableKey = !loading && !cancellationPending
    ? [...views].reverse().find((item) => (
      item.role === "assistant" && item.state === "settled" && Boolean(item.text)
    ))?.renderKey
    : undefined;
  const previousQuestion = views[index - 1]?.role === "user" ? views[index - 1]?.text : "";
  const followUps = showActions
    && message.renderKey === latestRegeneratableKey
    && sessionType === "consultation"
    && previousQuestion
    ? deriveConsultationFollowUps({
      question: previousQuestion,
      answer: message.text,
      theme,
      entrypoint: isGeneralDailyFortuneQuestion(previousQuestion) ? "daily_starlanguage" : null,
    })
    : [];
  return (
    <div className="message-entry">
      <ChatMessageRow message={message} />
      {showActions && (
        <ChatMessageActions
          feedback={messageFeedback[feedbackKey]}
          copied={copiedMessageKey === feedbackKey}
          canRegenerate={message.renderKey === latestRegeneratableKey}
          onFeedback={(requested) => actionsRef.current.onFeedback(feedbackKey, requested)}
          onCopy={() => actionsRef.current.onCopy(feedbackKey, message.text)}
          onRegenerate={() => actionsRef.current.onRegenerate(message.renderKey)}
        />
      )}
      <ConversationFollowUps
        questions={followUps}
        disabled={productEntrypointsDisabled}
        onSelect={(question) => actionsRef.current.onFollowUp(question)}
      />
    </div>
  );
}

const HistoryMessageEntry = memo(function HistoryMessageEntry(props: MessageEntryProps) {
  noteSettledRowRender();
  return <MessageEntry {...props} />;
});

/**
 * History rows: every settled message except the trailing assistant reply,
 * which `LatestAssistantEntry` owns so it keeps one identity from the first
 * streamed token through settlement.
 */
export const SettledMessageList = memo(function SettledMessageList({
  messages,
  excludeLatestAssistant = false,
  sessionId,
  sessionType,
  theme,
  messageFeedback,
  copiedMessageKey,
  loading,
  cancellationPending,
  productEntrypointsDisabled,
  actionsRef,
}: Omit<ChatTranscriptProps, "streamingText" | "streamingActivity" | "streamingThinking" | "streamingSections" | "streamingTimeline"> & {
  excludeLatestAssistant?: boolean;
}) {
  noteSettledListRender();
  const views = settledChatMessageViews(messages);
  const history = excludeLatestAssistant && views.at(-1)?.role === "assistant" ? views.slice(0, -1) : views;
  return (
    <>
      {history.map((message, index) => (
        <HistoryMessageEntry
          key={message.renderKey}
          message={message}
          views={views}
          index={index}
          sessionId={sessionId}
          sessionType={sessionType}
          theme={theme}
          messageFeedback={messageFeedback}
          copiedMessageKey={copiedMessageKey}
          loading={loading}
          cancellationPending={cancellationPending}
          productEntrypointsDisabled={productEntrypointsDisabled}
          actionsRef={actionsRef}
        />
      ))}
    </>
  );
});

/** The trailing assistant reply, streaming or settled, under one React identity. */
export const LatestAssistantEntry = memo(function LatestAssistantEntry(props: MessageEntryProps) {
  noteStreamingRowRender();
  useEffect(() => {
    noteLatestEntryMount();
  }, []);
  return <MessageEntry {...props} />;
});

export const ChatTranscript = memo(function ChatTranscript({
  messages,
  loading,
  streamingText,
  streamingActivity,
  streamingThinking,
  streamingSections,
  streamingTimeline,
  sessionId,
  sessionType,
  theme,
  messageFeedback,
  copiedMessageKey,
  cancellationPending,
  productEntrypointsDisabled,
  actionsRef,
}: ChatTranscriptProps) {
  const latest = latestAssistantView(
    messages,
    loading,
    streamingText,
    streamingActivity,
    streamingThinking,
    streamingSections,
    streamingTimeline,
  );

  return (
    <>
      <SettledMessageList
        messages={messages}
        excludeLatestAssistant
        loading={loading}
        sessionId={sessionId}
        sessionType={sessionType}
        theme={theme}
        messageFeedback={messageFeedback}
        copiedMessageKey={copiedMessageKey}
        cancellationPending={cancellationPending}
        productEntrypointsDisabled={productEntrypointsDisabled}
        actionsRef={actionsRef}
      />
      {latest ? (
        <LatestAssistantEntry
          key={latest.view.renderKey}
          message={latest.view}
          views={latest.views}
          index={latest.views.length - 1}
          sessionId={sessionId}
          sessionType={sessionType}
          theme={theme}
          messageFeedback={messageFeedback}
          copiedMessageKey={copiedMessageKey}
          loading={loading}
          cancellationPending={cancellationPending}
          productEntrypointsDisabled={productEntrypointsDisabled}
          actionsRef={actionsRef}
        />
      ) : null}
    </>
  );
});

export function UnsplitChatTranscript({
  messages,
  loading,
  streamingText,
  streamingActivity,
  streamingThinking,
  streamingSections,
  streamingTimeline,
  sessionId,
  sessionType,
  theme,
  messageFeedback,
  copiedMessageKey,
  cancellationPending,
  productEntrypointsDisabled,
  actionsRef,
}: ChatTranscriptProps) {
  noteUnsplitListRender();
  const views = chatMessageViews(
    messages,
    loading,
    streamingText,
    streamingActivity,
    streamingThinking,
    streamingSections,
    streamingTimeline,
  );
  return (
    <>
      {views.map((message, index) => {
        noteSettledRowRender();
        if (message.state !== "settled") noteStreamingRowRender();
        return (
          <MessageEntry
            key={message.renderKey}
            message={message}
            views={views}
            index={index}
            sessionId={sessionId}
            sessionType={sessionType}
            theme={theme}
            messageFeedback={messageFeedback}
            copiedMessageKey={copiedMessageKey}
            loading={loading}
            cancellationPending={cancellationPending}
            productEntrypointsDisabled={productEntrypointsDisabled}
            actionsRef={actionsRef}
          />
        );
      })}
    </>
  );
}

export { toggleChatMessageFeedback };
