import { describe, expect, it } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useSelection } from "./useSelection.js";

describe("useSelection", () => {
  it("starts with empty selection", () => {
    const { result } = renderHook(() => useSelection());
    expect(result.current.count).toBe(0);
    expect(result.current.selectedArray).toEqual([]);
  });

  it("toggles an item on", () => {
    const { result } = renderHook(() => useSelection());
    act(() => result.current.toggle("a"));
    expect(result.current.selectedIds.has("a")).toBe(true);
    expect(result.current.count).toBe(1);
  });

  it("toggles an item off", () => {
    const { result } = renderHook(() => useSelection());
    act(() => result.current.toggle("a"));
    act(() => result.current.toggle("a"));
    expect(result.current.selectedIds.has("a")).toBe(false);
    expect(result.current.count).toBe(0);
  });

  it("toggleAll selects all items when none are selected", () => {
    const { result } = renderHook(() => useSelection());
    act(() => result.current.toggleAll(["a", "b", "c"]));
    expect(result.current.count).toBe(3);
    expect(result.current.selectedIds.has("a")).toBe(true);
    expect(result.current.selectedIds.has("b")).toBe(true);
    expect(result.current.selectedIds.has("c")).toBe(true);
  });

  it("toggleAll deselects all items when all are selected", () => {
    const { result } = renderHook(() => useSelection());
    act(() => result.current.toggleAll(["a", "b"]));
    act(() => result.current.toggleAll(["a", "b"]));
    expect(result.current.count).toBe(0);
  });

  it("toggleAll selects remaining items when some are selected", () => {
    const { result } = renderHook(() => useSelection());
    act(() => result.current.toggle("a"));
    act(() => result.current.toggleAll(["a", "b", "c"]));
    expect(result.current.count).toBe(3);
  });

  it("clear removes all selections", () => {
    const { result } = renderHook(() => useSelection());
    act(() => {
      result.current.toggle("a");
      result.current.toggle("b");
    });
    act(() => result.current.clear());
    expect(result.current.count).toBe(0);
  });

  it("isAllSelected returns true when all given ids are selected", () => {
    const { result } = renderHook(() => useSelection());
    act(() => result.current.toggleAll(["a", "b"]));
    expect(result.current.isAllSelected(["a", "b"])).toBe(true);
  });

  it("isAllSelected returns false when some ids are not selected", () => {
    const { result } = renderHook(() => useSelection());
    act(() => result.current.toggle("a"));
    expect(result.current.isAllSelected(["a", "b"])).toBe(false);
  });

  it("isAllSelected returns false for empty ids array", () => {
    const { result } = renderHook(() => useSelection());
    expect(result.current.isAllSelected([])).toBe(false);
  });

  it("isIndeterminate returns true when some but not all are selected", () => {
    const { result } = renderHook(() => useSelection());
    act(() => result.current.toggle("a"));
    expect(result.current.isIndeterminate(["a", "b"])).toBe(true);
  });

  it("isIndeterminate returns false when all are selected", () => {
    const { result } = renderHook(() => useSelection());
    act(() => result.current.toggleAll(["a", "b"]));
    expect(result.current.isIndeterminate(["a", "b"])).toBe(false);
  });

  it("isIndeterminate returns false when none are selected", () => {
    const { result } = renderHook(() => useSelection());
    expect(result.current.isIndeterminate(["a", "b"])).toBe(false);
  });

  it("selectedArray reflects the current selection", () => {
    const { result } = renderHook(() => useSelection());
    act(() => {
      result.current.toggle("x");
      result.current.toggle("y");
    });
    expect(result.current.selectedArray.sort()).toEqual(["x", "y"]);
  });

  it("preserves other selections when toggling individual items", () => {
    const { result } = renderHook(() => useSelection());
    act(() => {
      result.current.toggle("a");
      result.current.toggle("b");
    });
    act(() => result.current.toggle("a"));
    expect(result.current.selectedIds.has("b")).toBe(true);
    expect(result.current.count).toBe(1);
  });
});
