/**
 * @file TerminalPanel.test.tsx
 * @description Unit tests for the TerminalPanel component
 */

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

// ==========================================
// Mocks
// ==========================================

// Mock XTerminal to avoid xterm.js DOM dependencies in panel tests
vi.mock("./XTerminal", () => ({
  XTerminal: vi.fn(({ token, isVisible }: { token: string; isVisible: boolean }) => (
    <div
      data-testid="mock-xterminal"
      data-token={token}
      data-visible={isVisible ? "true" : "false"}
    />
  )),
}));

import { TerminalPanel } from "./TerminalPanel";

// ==========================================
// Tests
// ==========================================

describe("TerminalPanel", () => {
  const onClose = vi.fn();
  const onTabChange = vi.fn();

  beforeEach(() => {
    vi.clearAllMocks();
  });

  // ==========================================
  // Rendering
  // ==========================================

  describe("rendering", () => {
    it("renders the terminal panel", () => {
      render((<TerminalPanel open={true} onClose={onClose} token="test-token" />) as ReactElement);
      expect(screen.getByRole("region", { name: "Terminal panel" })).toBeInTheDocument();
    });

    it("renders with height 280 when open", () => {
      render((<TerminalPanel open={true} onClose={onClose} token="test-token" />) as ReactElement);
      const panel = screen.getByRole("region", { name: "Terminal panel" });
      expect(panel).toHaveStyle({ height: "280px" });
    });

    it("renders with height 0 when closed", () => {
      const { container } = render(
        (<TerminalPanel open={false} onClose={onClose} token="test-token" />) as ReactElement
      );
      const panel = container.querySelector('[role="region"][aria-label="Terminal panel"]');
      expect(panel).toHaveStyle({ height: "0px" });
    });

    it("passes isVisible=true to XTerminal when open", () => {
      render((<TerminalPanel open={true} onClose={onClose} token="test-token" />) as ReactElement);
      const xterm = screen.getByTestId("mock-xterminal");
      expect(xterm).toHaveAttribute("data-visible", "true");
    });

    it("passes isVisible=false to XTerminal when closed", () => {
      const { container } = render(
        (<TerminalPanel open={false} onClose={onClose} token="test-token" />) as ReactElement
      );
      // Use container query since the element is inside an aria-hidden region
      const xterm = container.querySelector('[data-testid="mock-xterminal"]');
      expect(xterm).toHaveAttribute("data-visible", "false");
    });

    it("passes token to XTerminal", () => {
      render(
        (<TerminalPanel open={true} onClose={onClose} token="my-auth-token" />) as ReactElement
      );
      const xterm = screen.getByTestId("mock-xterminal");
      expect(xterm).toHaveAttribute("data-token", "my-auth-token");
    });
  });

  // ==========================================
  // Tab bar
  // ==========================================

  describe("tab bar", () => {
    it("renders default tabs when none provided", () => {
      render((<TerminalPanel open={true} onClose={onClose} token="test-token" />) as ReactElement);
      expect(screen.getByRole("tab", { name: "main" })).toBeInTheDocument();
    });

    it("renders custom tabs", () => {
      const tabs = [
        { id: "tab1", label: "Terminal 1" },
        { id: "tab2", label: "Terminal 2" },
      ];
      render(
        (
          <TerminalPanel open={true} onClose={onClose} tabs={tabs} token="test-token" />
        ) as ReactElement
      );
      expect(screen.getByRole("tab", { name: "Terminal 1" })).toBeInTheDocument();
      expect(screen.getByRole("tab", { name: "Terminal 2" })).toBeInTheDocument();
    });

    it("marks the active tab as selected", () => {
      const tabs = [
        { id: "tab1", label: "Tab 1" },
        { id: "tab2", label: "Tab 2" },
      ];
      render(
        (
          <TerminalPanel
            open={true}
            onClose={onClose}
            tabs={tabs}
            activeTab="tab2"
            token="test-token"
          />
        ) as ReactElement
      );
      const tab2 = screen.getByRole("tab", { name: "Tab 2" });
      expect(tab2).toHaveAttribute("aria-selected", "true");
    });

    it("calls onTabChange when a tab is clicked", () => {
      const tabs = [
        { id: "tab1", label: "Tab 1" },
        { id: "tab2", label: "Tab 2" },
      ];
      render(
        (
          <TerminalPanel
            open={true}
            onClose={onClose}
            tabs={tabs}
            onTabChange={onTabChange}
            token="test-token"
          />
        ) as ReactElement
      );
      fireEvent.click(screen.getByRole("tab", { name: "Tab 2" }));
      expect(onTabChange).toHaveBeenCalledWith("tab2");
    });
  });

  // ==========================================
  // Close button
  // ==========================================

  describe("close button", () => {
    it("renders the close button", () => {
      render((<TerminalPanel open={true} onClose={onClose} token="test-token" />) as ReactElement);
      expect(screen.getByRole("button", { name: "Close terminal" })).toBeInTheDocument();
    });

    it("calls onClose when close button is clicked", () => {
      render((<TerminalPanel open={true} onClose={onClose} token="test-token" />) as ReactElement);
      fireEvent.click(screen.getByRole("button", { name: "Close terminal" }));
      expect(onClose).toHaveBeenCalledTimes(1);
    });
  });

  // ==========================================
  // Accessibility
  // ==========================================

  describe("accessibility", () => {
    it("has aria-hidden=true when closed", () => {
      const { container } = render(
        (<TerminalPanel open={false} onClose={onClose} token="test-token" />) as ReactElement
      );
      // When aria-hidden=true, testing-library role queries ignore the element's aria-label.
      // Use a direct DOM query to verify the attribute.
      const panel = container.querySelector('[role="region"][aria-label="Terminal panel"]');
      expect(panel).toHaveAttribute("aria-hidden", "true");
    });

    it("has aria-hidden=false when open", () => {
      render((<TerminalPanel open={true} onClose={onClose} token="test-token" />) as ReactElement);
      const panel = screen.getByRole("region", { name: "Terminal panel" });
      expect(panel).toHaveAttribute("aria-hidden", "false");
    });

    it("has tablist role on the tab bar", () => {
      render((<TerminalPanel open={true} onClose={onClose} token="test-token" />) as ReactElement);
      expect(screen.getByRole("tablist")).toBeInTheDocument();
    });
  });
});
