/**
 * @file ChatOverlay.test.tsx
 * @description Tests for the ChatOverlay component
 */

import { render, screen, fireEvent } from "@testing-library/react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { ChatOverlay } from "./ChatOverlay";

// Mock the Chat component
vi.mock("./Chat", () => ({
  Chat: vi.fn(() => <div data-testid="chat-component">Chat Component</div>),
}));

// Mock the useChatOverlay hook
const mockOpen = vi.fn();
const mockClose = vi.fn();
const mockMinimize = vi.fn();
const mockExpand = vi.fn();
const mockToggle = vi.fn();
const mockToggleMinimize = vi.fn();

vi.mock("../../hooks/useChatOverlay", () => ({
  useChatOverlay: vi.fn(() => ({
    isOpen: false,
    isMinimized: false,
    open: mockOpen,
    close: mockClose,
    minimize: mockMinimize,
    expand: mockExpand,
    toggle: mockToggle,
    toggleMinimize: mockToggleMinimize,
  })),
}));

describe("ChatOverlay", () => {
  beforeEach(async () => {
    vi.clearAllMocks();
    // Reset mock to default state
    const { useChatOverlay } = await import("../../hooks/useChatOverlay");
    vi.mocked(useChatOverlay).mockReturnValue({
      isOpen: false,
      isMinimized: false,
      open: mockOpen,
      close: mockClose,
      minimize: mockMinimize,
      expand: mockExpand,
      toggle: mockToggle,
      toggleMinimize: mockToggleMinimize,
    });
  });

  describe("when closed", () => {
    it("should render a floating button to open the chat", () => {
      render(<ChatOverlay />);

      const openButton = screen.getByRole("button", { name: /open chat/i });
      expect(openButton).toBeDefined();
    });

    it("should not render the chat component when closed", () => {
      render(<ChatOverlay />);

      const chatComponent = screen.queryByTestId("chat-component");
      expect(chatComponent).toBeNull();
    });

    it("should call open when the floating button is clicked", () => {
      render(<ChatOverlay />);

      const openButton = screen.getByRole("button", { name: /open chat/i });
      fireEvent.click(openButton);

      expect(mockOpen).toHaveBeenCalledOnce();
    });
  });

  describe("when open", () => {
    beforeEach(async () => {
      const { useChatOverlay } = await import("../../hooks/useChatOverlay");
      vi.mocked(useChatOverlay).mockReturnValue({
        isOpen: true,
        isMinimized: false,
        open: mockOpen,
        close: mockClose,
        minimize: mockMinimize,
        expand: mockExpand,
        toggle: mockToggle,
        toggleMinimize: mockToggleMinimize,
      });
    });

    it("should render the chat component", () => {
      render(<ChatOverlay />);

      const chatComponent = screen.getByTestId("chat-component");
      expect(chatComponent).toBeDefined();
    });

    it("should render a close button", () => {
      render(<ChatOverlay />);

      const closeButton = screen.getByRole("button", { name: /close chat/i });
      expect(closeButton).toBeDefined();
    });

    it("should render a minimize button", () => {
      render(<ChatOverlay />);

      const minimizeButton = screen.getByRole("button", { name: /minimize chat/i });
      expect(minimizeButton).toBeDefined();
    });

    it("should call close when the close button is clicked", () => {
      render(<ChatOverlay />);

      const closeButton = screen.getByRole("button", { name: /close chat/i });
      fireEvent.click(closeButton);

      expect(mockClose).toHaveBeenCalledOnce();
    });

    it("should call minimize when the minimize button is clicked", () => {
      render(<ChatOverlay />);

      const minimizeButton = screen.getByRole("button", { name: /minimize chat/i });
      fireEvent.click(minimizeButton);

      expect(mockMinimize).toHaveBeenCalledOnce();
    });
  });

  describe("when minimized", () => {
    beforeEach(async () => {
      const { useChatOverlay } = await import("../../hooks/useChatOverlay");
      vi.mocked(useChatOverlay).mockReturnValue({
        isOpen: true,
        isMinimized: true,
        open: mockOpen,
        close: mockClose,
        minimize: mockMinimize,
        expand: mockExpand,
        toggle: mockToggle,
        toggleMinimize: mockToggleMinimize,
      });
    });

    it("should not render the chat component when minimized", () => {
      render(<ChatOverlay />);

      const chatComponent = screen.queryByTestId("chat-component");
      expect(chatComponent).toBeNull();
    });

    it("should render a minimized header", () => {
      render(<ChatOverlay />);

      const header = screen.getByText(/jarvis/i);
      expect(header).toBeDefined();
    });

    it("should call expand when clicking the minimized header", () => {
      render(<ChatOverlay />);

      const header = screen.getByText(/jarvis/i);
      fireEvent.click(header);

      expect(mockExpand).toHaveBeenCalledOnce();
    });
  });

  describe("keyboard shortcuts", () => {
    it("should toggle chat when Cmd+Shift+J is pressed", () => {
      render(<ChatOverlay />);

      fireEvent.keyDown(document, {
        key: "j",
        code: "KeyJ",
        metaKey: true,
        shiftKey: true,
      });

      expect(mockToggle).toHaveBeenCalledOnce();
    });

    it("should toggle chat when Ctrl+Shift+J is pressed", () => {
      render(<ChatOverlay />);

      fireEvent.keyDown(document, {
        key: "j",
        code: "KeyJ",
        ctrlKey: true,
        shiftKey: true,
      });

      expect(mockToggle).toHaveBeenCalledOnce();
    });

    it("should minimize chat when Escape is pressed and chat is open", async () => {
      const { useChatOverlay } = await import("../../hooks/useChatOverlay");
      vi.mocked(useChatOverlay).mockReturnValue({
        isOpen: true,
        isMinimized: false,
        open: mockOpen,
        close: mockClose,
        minimize: mockMinimize,
        expand: mockExpand,
        toggle: mockToggle,
        toggleMinimize: mockToggleMinimize,
      });

      render(<ChatOverlay />);

      fireEvent.keyDown(document, {
        key: "Escape",
        code: "Escape",
      });

      expect(mockMinimize).toHaveBeenCalledOnce();
    });

    it("should open chat when Cmd+K is pressed and chat is closed", async () => {
      render(<ChatOverlay />);

      // Wait for component to mount
      await screen.findByRole("button", { name: /open chat/i });

      fireEvent.keyDown(document, {
        key: "k",
        code: "KeyK",
        metaKey: true,
      });

      expect(mockOpen).toHaveBeenCalled();
    });

    it("should open chat when Ctrl+K is pressed and chat is closed", async () => {
      render(<ChatOverlay />);

      // Wait for component to mount
      await screen.findByRole("button", { name: /open chat/i });

      fireEvent.keyDown(document, {
        key: "k",
        code: "KeyK",
        ctrlKey: true,
      });

      expect(mockOpen).toHaveBeenCalled();
    });
  });

  describe("new conversation button", () => {
    it("should render the new conversation button when chat is open", async () => {
      const { useChatOverlay } = await import("../../hooks/useChatOverlay");
      vi.mocked(useChatOverlay).mockReturnValue({
        isOpen: true,
        isMinimized: false,
        open: mockOpen,
        close: mockClose,
        minimize: mockMinimize,
        expand: mockExpand,
        toggle: mockToggle,
        toggleMinimize: mockToggleMinimize,
      });

      render(<ChatOverlay />);

      const newConvBtn = screen.getByRole("button", { name: /new conversation/i });
      expect(newConvBtn).toBeDefined();
    });

    it("should have a tooltip on the new conversation button", async () => {
      const { useChatOverlay } = await import("../../hooks/useChatOverlay");
      vi.mocked(useChatOverlay).mockReturnValue({
        isOpen: true,
        isMinimized: false,
        open: mockOpen,
        close: mockClose,
        minimize: mockMinimize,
        expand: mockExpand,
        toggle: mockToggle,
        toggleMinimize: mockToggleMinimize,
      });

      render(<ChatOverlay />);

      const newConvBtn = screen.getByRole("button", { name: /new conversation/i });
      expect(newConvBtn.getAttribute("title")).toContain("Cmd+N");
    });
  });

  describe("responsive design", () => {
    it("should render as a sidebar on desktop", () => {
      render(<ChatOverlay />);

      // Check for desktop-specific classes (will be verified in implementation)
      // This is a placeholder - actual implementation will have proper responsive classes
      expect(true).toBe(true);
    });

    it("should render as a drawer on mobile", () => {
      render(<ChatOverlay />);

      // Check for mobile-specific classes (will be verified in implementation)
      // This is a placeholder - actual implementation will have proper responsive classes
      expect(true).toBe(true);
    });
  });
});
