import { fireEvent, render, screen } from "@solidjs/testing-library";
import { describe, expect, it, vi } from "vitest";
import { Listbox } from "../../../src/components/listbox/index";

describe("Listbox — roles and selection", () => {
  it("root has role=listbox", () => {
    render(() => (
      <Listbox items={["a", "b", "c"]}>
        <Listbox.Item value="a">A</Listbox.Item>
        <Listbox.Item value="b">B</Listbox.Item>
        <Listbox.Item value="c">C</Listbox.Item>
      </Listbox>
    ));
    expect(screen.getByRole("listbox")).toBeTruthy();
  });

  it("items have role=option", () => {
    render(() => (
      <Listbox items={["a", "b"]}>
        <Listbox.Item value="a">A</Listbox.Item>
        <Listbox.Item value="b">B</Listbox.Item>
      </Listbox>
    ));
    expect(screen.getAllByRole("option")).toHaveLength(2);
  });

  it("aria-selected reflects selection", () => {
    render(() => (
      <Listbox items={["a", "b"]} defaultValue="b">
        <Listbox.Item value="a">A</Listbox.Item>
        <Listbox.Item value="b">B</Listbox.Item>
      </Listbox>
    ));
    const options = screen.getAllByRole("option");
    expect(options[0].getAttribute("aria-selected")).toBe("false");
    expect(options[1].getAttribute("aria-selected")).toBe("true");
  });

  it("click selects item", () => {
    const onChange = vi.fn();
    render(() => (
      <Listbox items={["a", "b"]} onValueChange={onChange}>
        <Listbox.Item value="a">A</Listbox.Item>
        <Listbox.Item value="b">B</Listbox.Item>
      </Listbox>
    ));
    fireEvent.click(screen.getAllByRole("option")[1]);
    expect(onChange).toHaveBeenCalledWith("b");
  });

  it("multiple selection mode works", () => {
    const onChange = vi.fn();
    render(() => (
      <Listbox items={["a", "b", "c"]} selectionMode="multiple" onValuesChange={onChange}>
        <Listbox.Item value="a">A</Listbox.Item>
        <Listbox.Item value="b">B</Listbox.Item>
        <Listbox.Item value="c">C</Listbox.Item>
      </Listbox>
    ));
    const listbox = screen.getByRole("listbox");
    expect(listbox.getAttribute("aria-multiselectable")).toBe("true");
    fireEvent.click(screen.getAllByRole("option")[0]);
    expect(onChange).toHaveBeenCalledWith(["a"]);
  });
});

describe("Listbox — keyboard navigation", () => {
  it("ArrowDown highlights next item", () => {
    render(() => (
      <Listbox items={["a", "b", "c"]}>
        <Listbox.Item value="a">A</Listbox.Item>
        <Listbox.Item value="b">B</Listbox.Item>
        <Listbox.Item value="c">C</Listbox.Item>
      </Listbox>
    ));
    const listbox = screen.getByRole("listbox");
    listbox.focus();
    fireEvent.keyDown(listbox, { key: "ArrowDown" });
    fireEvent.keyDown(listbox, { key: "ArrowDown" });
    const highlighted = listbox.getAttribute("aria-activedescendant");
    expect(highlighted).toBeTruthy();
  });

  it("Enter selects highlighted item", () => {
    const onChange = vi.fn();
    render(() => (
      <Listbox items={["a", "b", "c"]} onValueChange={onChange}>
        <Listbox.Item value="a">A</Listbox.Item>
        <Listbox.Item value="b">B</Listbox.Item>
        <Listbox.Item value="c">C</Listbox.Item>
      </Listbox>
    ));
    const listbox = screen.getByRole("listbox");
    listbox.focus();
    fireEvent.keyDown(listbox, { key: "ArrowDown" });
    fireEvent.keyDown(listbox, { key: "Enter" });
    expect(onChange).toHaveBeenCalledWith("a");
  });

  it("Home/End navigate to first/last", () => {
    render(() => (
      <Listbox items={["a", "b", "c"]}>
        <Listbox.Item value="a">A</Listbox.Item>
        <Listbox.Item value="b">B</Listbox.Item>
        <Listbox.Item value="c">C</Listbox.Item>
      </Listbox>
    ));
    const listbox = screen.getByRole("listbox");
    listbox.focus();
    fireEvent.keyDown(listbox, { key: "End" });
    const options = screen.getAllByRole("option");
    expect(options[2].getAttribute("data-highlighted")).toBe("");
  });
});
