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

// Helper: render inside a table/thead/tr to satisfy HTML semantics
function renderInTable(ui: React.ReactElement) {
  return render(
    <table>
      <thead>
        <tr>{ui}</tr>
      </thead>
    </table>,
  );
}

describe("SortableColumnHeader", () => {
  describe("rendering", () => {
    it("renders the label text", () => {
      renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField={null}
          sortDir={null}
          onSort={vi.fn()}
        />,
      );
      expect(screen.getByText("Name")).toBeInTheDocument();
    });

    it("renders a button for the sortable label", () => {
      renderInTable(
        <SortableColumnHeader
          label="Budget"
          field="budget"
          sortField={null}
          sortDir={null}
          onSort={vi.fn()}
        />,
      );
      expect(screen.getByRole("button", { name: /budget/i })).toBeInTheDocument();
    });

    it("renders inside a <th> element", () => {
      const { container } = renderInTable(
        <SortableColumnHeader
          label="Status"
          field="status"
          sortField={null}
          sortDir={null}
          onSort={vi.fn()}
        />,
      );
      expect(container.querySelector("th")).toBeInTheDocument();
    });
  });

  describe("sort direction icons", () => {
    it("shows no active direction when sortField does not match field", () => {
      const { container } = renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField="budget"
          sortDir="asc"
          onSort={vi.fn()}
        />,
      );
      // Neither chevron should be brand-colored
      const paths = container.querySelectorAll("path");
      paths.forEach((path) => {
        expect(path.className.baseVal).not.toContain("stroke-brand-600");
      });
    });

    it("highlights the up chevron when sorted asc on this field", () => {
      const { container } = renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField="name"
          sortDir="asc"
          onSort={vi.fn()}
        />,
      );
      const paths = container.querySelectorAll("path");
      // First path = up chevron (asc)
      expect(paths[0]?.className.baseVal).toContain("stroke-brand-600");
      // Second path = down chevron should be gray
      expect(paths[1]?.className.baseVal).toContain("stroke-gray-300");
    });

    it("highlights the down chevron when sorted desc on this field", () => {
      const { container } = renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField="name"
          sortDir="desc"
          onSort={vi.fn()}
        />,
      );
      const paths = container.querySelectorAll("path");
      // First path = up chevron should be gray
      expect(paths[0]?.className.baseVal).toContain("stroke-gray-300");
      // Second path = down chevron (desc)
      expect(paths[1]?.className.baseVal).toContain("stroke-brand-600");
    });

    it("shows no active direction when sortDir is null for this field", () => {
      const { container } = renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField="name"
          sortDir={null}
          onSort={vi.fn()}
        />,
      );
      const paths = container.querySelectorAll("path");
      paths.forEach((path) => {
        expect(path.className.baseVal).not.toContain("stroke-brand-600");
      });
    });
  });

  describe("interactions", () => {
    it("calls onSort with the field when the button is clicked", async () => {
      const user = userEvent.setup();
      const handleSort = vi.fn();
      renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField={null}
          sortDir={null}
          onSort={handleSort}
        />,
      );
      await user.click(screen.getByRole("button", { name: /name/i }));
      expect(handleSort).toHaveBeenCalledOnce();
      expect(handleSort).toHaveBeenCalledWith("name");
    });

    it("passes the correct field string when multiple columns exist", async () => {
      const user = userEvent.setup();
      const handleSort = vi.fn();
      render(
        <table>
          <thead>
            <tr>
              <SortableColumnHeader
                label="Name"
                field="name"
                sortField={null}
                sortDir={null}
                onSort={handleSort}
              />
              <SortableColumnHeader
                label="Budget"
                field="budget"
                sortField={null}
                sortDir={null}
                onSort={handleSort}
              />
            </tr>
          </thead>
        </table>,
      );
      await user.click(screen.getByRole("button", { name: /budget/i }));
      expect(handleSort).toHaveBeenCalledWith("budget");
    });
  });

  describe("alignment", () => {
    it("applies justify-start for left alignment (default)", () => {
      const { container } = renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField={null}
          sortDir={null}
          onSort={vi.fn()}
        />,
      );
      const div = container.querySelector("th > div");
      expect(div?.className).toContain("justify-start");
    });

    it("applies justify-end for right alignment", () => {
      const { container } = renderInTable(
        <SortableColumnHeader
          label="Amount"
          field="amount"
          sortField={null}
          sortDir={null}
          onSort={vi.fn()}
          align="right"
        />,
      );
      const div = container.querySelector("th > div");
      expect(div?.className).toContain("justify-end");
    });

    it("applies justify-center for center alignment", () => {
      const { container } = renderInTable(
        <SortableColumnHeader
          label="Status"
          field="status"
          sortField={null}
          sortDir={null}
          onSort={vi.fn()}
          align="center"
        />,
      );
      const div = container.querySelector("th > div");
      expect(div?.className).toContain("justify-center");
    });
  });

  describe("tooltip", () => {
    it("does not render an info tooltip when tooltip prop is absent", () => {
      renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField={null}
          sortDir={null}
          onSort={vi.fn()}
        />,
      );
      expect(screen.queryByRole("button", { name: "More information" })).not.toBeInTheDocument();
    });

    it("renders an info tooltip button when tooltip prop is provided", () => {
      renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField={null}
          sortDir={null}
          onSort={vi.fn()}
          tooltip="Helpful hint"
        />,
      );
      expect(screen.getByRole("button", { name: "More information" })).toBeInTheDocument();
    });
  });

  describe("custom className", () => {
    it("forwards className to the <th> element", () => {
      const { container } = renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField={null}
          sortDir={null}
          onSort={vi.fn()}
          className="w-48"
        />,
      );
      expect(container.querySelector("th")?.className).toContain("w-48");
    });
  });

  describe("ARIA semantics", () => {
    it("sets aria-sort='ascending' on <th> when sorted asc", () => {
      renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField="name"
          sortDir="asc"
          onSort={vi.fn()}
        />,
      );
      const th = document.querySelector("th");
      expect(th).toHaveAttribute("aria-sort", "ascending");
    });

    it("sets aria-sort='descending' on <th> when sorted desc", () => {
      renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField="name"
          sortDir="desc"
          onSort={vi.fn()}
        />,
      );
      const th = document.querySelector("th");
      expect(th).toHaveAttribute("aria-sort", "descending");
    });

    it("does not set aria-sort when this field is not the active sort", () => {
      renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField="budget"
          sortDir="asc"
          onSort={vi.fn()}
        />,
      );
      const th = document.querySelector("th");
      expect(th).not.toHaveAttribute("aria-sort");
    });

    it("does not set aria-sort when sortDir is null", () => {
      renderInTable(
        <SortableColumnHeader
          label="Name"
          field="name"
          sortField="name"
          sortDir={null}
          onSort={vi.fn()}
        />,
      );
      const th = document.querySelector("th");
      expect(th).not.toHaveAttribute("aria-sort");
    });
  });
});
