import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, act } from "@testing-library/react";
import { AnimatedTerminal } from "../AnimatedTerminal";

// Mock matchMedia for prefers-reduced-motion
function mockMatchMedia(matches: boolean) {
  Object.defineProperty(window, "matchMedia", {
    writable: true,
    value: vi.fn().mockImplementation((query) => ({
      matches,
      media: query,
      onchange: null,
      addListener: vi.fn(),
      removeListener: vi.fn(),
      addEventListener: vi.fn(),
      removeEventListener: vi.fn(),
      dispatchEvent: vi.fn(),
    })),
  });
}

describe("AnimatedTerminal", () => {
  beforeEach(() => {
    vi.useFakeTimers();
    mockMatchMedia(false); // no reduced motion by default
  });

  afterEach(() => {
    vi.useRealTimers();
    vi.restoreAllMocks();
  });

  it("renders the terminal chrome with label", () => {
    const { getByText } = render(<AnimatedTerminal />);
    expect(getByText("Terminal")).toBeTruthy();
  });

  it("renders the terminal glass container", () => {
    const { container } = render(<AnimatedTerminal />);
    const wrapper = container.querySelector(".glass");
    expect(wrapper).toBeTruthy();
  });

  it("shows all lines instantly when prefers-reduced-motion is set", () => {
    mockMatchMedia(true); // reduced motion
    const { container } = render(<AnimatedTerminal />);
    // All script lines should be visible immediately
    expect(container.textContent).toMatch(/llmhosts serve/);
    expect(container.textContent).toMatch(/llmhosts tunnel/);
  });

  it("starts with no terminal lines before animation begins", () => {
    const { container } = render(<AnimatedTerminal />);
    const lines = container.querySelectorAll("[data-testid='terminal-line']");
    expect(lines.length).toBe(0);
  });

  it("shows first character of input after initial delay", () => {
    const { container } = render(<AnimatedTerminal />);

    act(() => {
      vi.advanceTimersByTime(700);
    });

    // At least one character should appear in the terminal body
    expect(container.textContent?.length).toBeGreaterThan(10); // chrome + at least 1 char
  });

  it("shows output lines after typing completes", () => {
    const { container } = render(<AnimatedTerminal />);

    act(() => {
      vi.advanceTimersByTime(5000);
    });

    // Several lines of content should be visible by now
    const lines = container.querySelectorAll("[data-testid='terminal-line']");
    expect(lines.length).toBeGreaterThan(2);
  });

  it("loops: terminal chrome persists across the full sequence", () => {
    const { getByText } = render(<AnimatedTerminal />);

    act(() => {
      vi.advanceTimersByTime(15000);
    });

    // Terminal chrome should always be present, even during reset
    expect(getByText("Terminal")).toBeTruthy();
  });
});
