import { describe, expect, it, vi } from "vitest";
import { render, screen } from "~/test-utils.js";
import userEvent from "@testing-library/user-event";
import { InfoTooltip } from "./InfoTooltip.js";

// InfoTooltip uses createPortal – jsdom supports document.body so portals work,
// but getBoundingClientRect returns all-zeros which is fine for logic tests.

describe("InfoTooltip", () => {
  describe("trigger button", () => {
    it("renders a button with accessible label", () => {
      render(<InfoTooltip content="Help text" />);
      const btn = screen.getByRole("button", { name: /more information/i });
      expect(btn).toBeInTheDocument();
    });

    it("shows the letter i inside the button", () => {
      render(<InfoTooltip content="Help text" />);
      expect(screen.getByRole("button", { name: /more information/i })).toHaveTextContent("i");
    });
  });

  describe("hover interaction", () => {
    it("shows tooltip content on mouse enter", async () => {
      const user = userEvent.setup();
      render(<InfoTooltip content="Hover help" />);
      const btn = screen.getByRole("button", { name: /more information/i });
      await user.hover(btn);
      expect(screen.getByText("Hover help")).toBeInTheDocument();
    });

    it("hides tooltip content on mouse leave", async () => {
      const user = userEvent.setup();
      render(<InfoTooltip content="Hover help" />);
      const btn = screen.getByRole("button", { name: /more information/i });
      await user.hover(btn);
      expect(screen.getByText("Hover help")).toBeInTheDocument();
      await user.unhover(btn);
      expect(screen.queryByText("Hover help")).not.toBeInTheDocument();
    });
  });

  describe("focus interaction", () => {
    it("shows tooltip on focus", async () => {
      const user = userEvent.setup();
      render(<InfoTooltip content="Focus help" />);
      const btn = screen.getByRole("button", { name: /more information/i });
      await user.tab(); // move focus to the button
      expect(screen.getByText("Focus help")).toBeInTheDocument();
    });

    it("hides tooltip on blur", async () => {
      const user = userEvent.setup();
      render(
        <>
          <InfoTooltip content="Focus help" />
          <button>Other</button>
        </>,
      );
      const btn = screen.getByRole("button", { name: /more information/i });
      await user.tab(); // focus the info button
      expect(screen.getByText("Focus help")).toBeInTheDocument();
      await user.tab(); // move focus away → blur fires
      expect(screen.queryByText("Focus help")).not.toBeInTheDocument();
    });
  });

  describe("content", () => {
    it("renders plain string content inside the tooltip", async () => {
      const user = userEvent.setup();
      render(<InfoTooltip content="Plain string" />);
      await user.hover(screen.getByRole("button", { name: /more information/i }));
      expect(screen.getByText("Plain string")).toBeInTheDocument();
    });

    it("renders JSX content inside the tooltip", async () => {
      const user = userEvent.setup();
      render(
        <InfoTooltip
          content={
            <span data-testid="rich-content">
              <strong>Bold</strong> text
            </span>
          }
        />,
      );
      await user.hover(screen.getByRole("button", { name: /more information/i }));
      expect(screen.getByTestId("rich-content")).toBeInTheDocument();
      expect(screen.getByText("Bold")).toBeInTheDocument();
    });
  });

  describe("position prop", () => {
    it("defaults to top position (no explicit position needed)", async () => {
      const user = userEvent.setup();
      const { container } = render(<InfoTooltip content="Top tip" />);
      await user.hover(screen.getByRole("button", { name: /more information/i }));
      // The tooltip div should be in the document (rendered via portal into body)
      expect(document.body.textContent).toContain("Top tip");
      // Arrow class for top position includes border-t-gray-900
      // Look for the arrow span inside the tooltip
      const arrows = document.querySelectorAll('[class*="border-t-gray-900"]');
      expect(arrows.length).toBeGreaterThan(0);
    });

    it("renders with bottom position without throwing", async () => {
      const user = userEvent.setup();
      render(<InfoTooltip content="Bottom tip" position="bottom" />);
      await user.hover(screen.getByRole("button", { name: /more information/i }));
      expect(document.body.textContent).toContain("Bottom tip");
    });
  });

  describe("width prop", () => {
    it("applies default width class w-60 to the tooltip", async () => {
      const user = userEvent.setup();
      render(<InfoTooltip content="Width test" />);
      await user.hover(screen.getByRole("button", { name: /more information/i }));
      // Find the tooltip container div rendered in the portal
      // It has the width class directly on the tooltip wrapper
      const tooltipEl = document.body.querySelector(".w-60");
      expect(tooltipEl).toBeTruthy();
    });

    it("applies custom width class when width prop is provided", async () => {
      const user = userEvent.setup();
      render(<InfoTooltip content="Wide tip" width="w-72" />);
      await user.hover(screen.getByRole("button", { name: /more information/i }));
      const tooltipEl = document.body.querySelector(".w-72");
      expect(tooltipEl).toBeTruthy();
    });
  });

  describe("portal rendering", () => {
    it("renders tooltip into document.body (not inside the component root)", async () => {
      const user = userEvent.setup();
      const { container } = render(
        <div data-testid="component-root">
          <InfoTooltip content="Portal check" />
        </div>,
      );
      await user.hover(screen.getByRole("button", { name: /more information/i }));
      // Tooltip text should NOT be inside the component root
      expect(container.querySelector('[data-testid="component-root"]')?.textContent).not.toContain(
        "Portal check",
      );
      // But it IS present in document.body
      expect(document.body.textContent).toContain("Portal check");
    });
  });
});
