import { createRoot, createSignal } from "solid-js";
import { describe, expect, it, vi } from "vitest";
import { createListNavigation } from "../../src/primitives/create-list-navigation";

describe("createListNavigation — highlighting", () => {
  it("highlights first item via highlightFirst", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
      });
      expect(nav.highlightedValue()).toBeUndefined();
      nav.highlightFirst();
      expect(nav.highlightedValue()).toBe("a");
      dispose();
    });
  });

  it("highlights last item via highlightLast", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
      });
      nav.highlightLast();
      expect(nav.highlightedValue()).toBe("c");
      dispose();
    });
  });

  it("clears highlight via clearHighlight", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
      });
      nav.highlightFirst();
      nav.clearHighlight();
      expect(nav.highlightedValue()).toBeUndefined();
      dispose();
    });
  });
});

describe("createListNavigation — arrow keys", () => {
  it("ArrowDown highlights next item", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
      });
      nav.highlightFirst();
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "ArrowDown" }),
      );
      expect(nav.highlightedValue()).toBe("b");
      dispose();
    });
  });

  it("ArrowUp highlights previous item", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
      });
      nav.highlight("c");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "ArrowUp" }),
      );
      expect(nav.highlightedValue()).toBe("b");
      dispose();
    });
  });

});

describe("createListNavigation — loop behavior", () => {
  it("wraps around when loop is true (default)", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
      });
      nav.highlight("c");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "ArrowDown" }),
      );
      expect(nav.highlightedValue()).toBe("a");
      dispose();
    });
  });

  it("does not wrap when loop is false", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
        loop: false,
      });
      nav.highlight("c");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "ArrowDown" }),
      );
      expect(nav.highlightedValue()).toBe("c");
      dispose();
    });
  });
});

describe("createListNavigation — Home/End keys", () => {
  it("Home highlights first, End highlights last", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
      });
      nav.highlight("b");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "End" }),
      );
      expect(nav.highlightedValue()).toBe("c");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "Home" }),
      );
      expect(nav.highlightedValue()).toBe("a");
      dispose();
    });
  });
});

describe("createListNavigation — selection mode", () => {
  it("Enter selects highlighted item", () => {
    createRoot((dispose) => {
      const onChange = vi.fn();
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
        onValueChange: onChange,
      });
      nav.highlight("b");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "Enter" }),
      );
      expect(onChange).toHaveBeenCalledWith("b");
      dispose();
    });
  });

  it("Space selects highlighted item", () => {
    createRoot((dispose) => {
      const onChange = vi.fn();
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
        onValueChange: onChange,
      });
      nav.highlight("a");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: " " }),
      );
      expect(onChange).toHaveBeenCalledWith("a");
      dispose();
    });
  });

  it("selectedValue reflects controlled value", () => {
    createRoot((dispose) => {
      const [value, setValue] = createSignal<string | undefined>("b");
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
        value,
        onValueChange: setValue,
      });
      expect(nav.selectedValue()).toBe("b");
      dispose();
    });
  });
});

describe("createListNavigation — activation mode", () => {
  it("Enter calls onActivate", () => {
    createRoot((dispose) => {
      const onActivate = vi.fn();
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "activation",
        baseId: "test",
        onActivate,
      });
      nav.highlight("b");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "Enter" }),
      );
      expect(onActivate).toHaveBeenCalledWith("b");
      dispose();
    });
  });
});

describe("createListNavigation — item props", () => {
  it("returns correct id and role for selection mode", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b"],
        mode: "selection",
        baseId: "test",
      });
      const props = nav.getItemProps("a");
      expect(props.id).toBe("test-option-a");
      expect(props.role).toBe("option");
      dispose();
    });
  });

  it("returns menuitem role for activation mode", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a"],
        mode: "activation",
        baseId: "test",
      });
      const props = nav.getItemProps("a");
      expect(props.role).toBe("menuitem");
      dispose();
    });
  });

  it("marks highlighted item", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b"],
        mode: "selection",
        baseId: "test",
      });
      nav.highlight("a");
      expect(nav.getItemProps("a")["data-highlighted"]).toBe("");
      expect(nav.getItemProps("b")["data-highlighted"]).toBeUndefined();
      dispose();
    });
  });
});

describe("createListNavigation — container props", () => {
  it("has correct role", () => {
    createRoot((dispose) => {
      const selNav = createListNavigation({
        items: () => ["a"],
        mode: "selection",
        baseId: "test",
      });
      expect(selNav.containerProps.role).toBe("listbox");

      const actNav = createListNavigation({
        items: () => ["a"],
        mode: "activation",
        baseId: "test2",
      });
      expect(actNav.containerProps.role).toBe("menu");
      dispose();
    });
  });

  it("aria-activedescendant tracks highlighted item", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b"],
        mode: "selection",
        baseId: "test",
      });
      expect(nav.containerProps["aria-activedescendant"]).toBeUndefined();
      nav.highlight("b");
      expect(nav.containerProps["aria-activedescendant"]).toBe(
        "test-option-b",
      );
      dispose();
    });
  });
});

describe("createListNavigation — typeahead", () => {
  it("typing a character highlights matching item", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["apple", "banana", "cherry"],
        mode: "selection",
        baseId: "test",
        getLabel: (v) => v,
      });
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "b" }),
      );
      expect(nav.highlightedValue()).toBe("banana");
      dispose();
    });
  });
});

describe("createListNavigation — reactive items", () => {
  it("highlight resets when highlighted item is removed", () => {
    createRoot((dispose) => {
      const [items, setItems] = createSignal(["a", "b", "c"]);
      const nav = createListNavigation({
        items,
        mode: "selection",
        baseId: "test",
      });
      nav.highlight("b");
      expect(nav.highlightedValue()).toBe("b");
      setItems(["a", "c"]);
      expect(nav.highlightedValue()).toBeUndefined();
      dispose();
    });
  });
});

describe("createListNavigation — horizontal orientation", () => {
  it("ArrowRight navigates in horizontal mode", () => {
    createRoot((dispose) => {
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
        orientation: "horizontal",
      });
      nav.highlightFirst();
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "ArrowRight" }),
      );
      expect(nav.highlightedValue()).toBe("b");
      dispose();
    });
  });
});

describe("createListNavigation — multiple selection", () => {
  it("toggles items on and off", () => {
    createRoot((dispose) => {
      const onChange = vi.fn();
      const nav = createListNavigation({
        items: () => ["a", "b", "c"],
        mode: "selection",
        baseId: "test",
        multiple: true,
        onValuesChange: onChange,
      });
      nav.highlight("a");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "Enter" }),
      );
      expect(onChange).toHaveBeenCalledWith(["a"]);
      nav.highlight("b");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "Enter" }),
      );
      expect(onChange).toHaveBeenCalledWith(["a", "b"]);
      nav.highlight("a");
      nav.containerProps.onKeyDown(
        new KeyboardEvent("keydown", { key: "Enter" }),
      );
      expect(onChange).toHaveBeenCalledWith(["b"]);
      dispose();
    });
  });
});
