/* eslint-disable @next/next/no-img-element */
import "@testing-library/jest-dom";
import React from "react";
import { render, screen } from "@testing-library/react";

import { AgentWorkspace } from "./AgentWorkspace";
import type { Message } from "./GlobalChatbox.types";

const renderCounts = new Map<string, number>();
const mountCounts = new Map<string, number>();
const unmountCounts = new Map<string, number>();
const streamingFlags = new Map<string, boolean>();

jest.mock("next/image", () => ({
  __esModule: true,
  default: (props: React.ImgHTMLAttributes<HTMLImageElement>) => <img {...props} alt={props.alt ?? ""} />,
}));

jest.mock("framer-motion", () => ({
  AnimatePresence: ({ children }: { children: React.ReactNode }) => <>{children}</>,
  motion: {
    div: ({
      children,
      animate: _animate,
      exit: _exit,
      initial: _initial,
      layout: _layout,
      transition: _transition,
      whileHover: _whileHover,
      ...props
    }: React.HTMLAttributes<HTMLDivElement> & Record<string, unknown>) => (
      <div {...props}>{children}</div>
    ),
  },
}));

jest.mock("./AgentTurn", () => ({
  AgentTurn: ({ message, isStreaming }: { message: Message; isStreaming: boolean }) => {
    React.useEffect(() => {
      mountCounts.set(message.id, (mountCounts.get(message.id) ?? 0) + 1);
      return () => {
        unmountCounts.set(message.id, (unmountCounts.get(message.id) ?? 0) + 1);
      };
    }, [message.id]);
    renderCounts.set(message.id, (renderCounts.get(message.id) ?? 0) + 1);
    streamingFlags.set(message.id, isStreaming);
    return <div data-testid={`turn-${message.id}`}>{message.content}</div>;
  },
}));

describe("AgentWorkspace", () => {
  const defaultProps = {
    bottomRef: { current: null },
    speakingMessageId: null,
    speechState: "idle" as const,
    onSpeak: jest.fn(),
    onPauseSpeech: jest.fn(),
    onResumeSpeech: jest.fn(),
    onStopSpeech: jest.fn(),
    isTtsSupported: false,
    onCreateBranch: jest.fn(),
    onReplyPermission: jest.fn(),
    onReplyQuestion: jest.fn(),
    onRejectQuestion: jest.fn(),
  };

  beforeEach(() => {
    renderCounts.clear();
    mountCounts.clear();
    unmountCounts.clear();
    streamingFlags.clear();
  });

  it("shows a loading skeleton instead of the empty state while switching history sessions", () => {
    render(
      <AgentWorkspace
        {...defaultProps}
        isStreaming={false}
        isLoadingSession
        messages={[]}
      />,
    );

    expect(screen.getByLabelText("正在加载历史记录")).toBeInTheDocument();
    expect(screen.queryByText("我已就绪，请描述任务")).not.toBeInTheDocument();
  });

  it("keeps stable history turns from re-rendering while the last assistant message streams", () => {
    const userMessage: Message = {
      id: "user-1",
      role: "user",
      content: "question",
    };
    const assistantHistoryMessage: Message = {
      id: "assistant-1",
      role: "assistant",
      content: "stable answer",
    };
    const streamingMessage: Message = {
      id: "assistant-2",
      role: "assistant",
      content: "partial",
    };

    const { rerender } = render(
      <AgentWorkspace
        {...defaultProps}
        isStreaming
        messages={[userMessage, assistantHistoryMessage, streamingMessage]}
      />,
    );

    const updatedStreamingMessage: Message = {
      ...streamingMessage,
      content: "partial with more tokens",
    };

    rerender(
      <AgentWorkspace
        {...defaultProps}
        isStreaming
        messages={[userMessage, assistantHistoryMessage, updatedStreamingMessage]}
      />,
    );

    expect(renderCounts.get("user-1")).toBe(1);
    expect(renderCounts.get("assistant-1")).toBe(1);
    expect(renderCounts.get("assistant-2")).toBe(2);
    expect(streamingFlags.get("assistant-1")).toBe(false);
    expect(streamingFlags.get("assistant-2")).toBe(true);
  });

  it("does not remount the streaming assistant turn when streaming finishes", () => {
    const userMessage: Message = {
      id: "user-1",
      role: "user",
      content: "question",
    };
    const assistantMessage: Message = {
      id: "assistant-1",
      role: "assistant",
      content: "final answer",
    };

    const { rerender } = render(
      <AgentWorkspace
        {...defaultProps}
        isStreaming
        messages={[userMessage, assistantMessage]}
      />,
    );

    expect(streamingFlags.get("assistant-1")).toBe(true);

    rerender(
      <AgentWorkspace
        {...defaultProps}
        isStreaming={false}
        messages={[userMessage, assistantMessage]}
      />,
    );

    expect(mountCounts.get("assistant-1")).toBe(1);
    expect(unmountCounts.get("assistant-1") ?? 0).toBe(0);
    expect(streamingFlags.get("assistant-1")).toBe(false);
  });
});
