import { createRoot } from "solid-js";
import { describe, expect, it, vi } from "vitest";
import { createDisclosureState } from "../../src/primitives/create-disclosure-state";

describe("createDisclosureState", () => {
  it("starts closed by default", () => {
    createRoot((dispose) => {
      const state = createDisclosureState({});
      expect(state.isOpen()).toBe(false);
      dispose();
    });
  });

  it("respects defaultOpen", () => {
    createRoot((dispose) => {
      const state = createDisclosureState({ defaultOpen: true });
      expect(state.isOpen()).toBe(true);
      dispose();
    });
  });

  it("open() sets state to true", () => {
    createRoot((dispose) => {
      const state = createDisclosureState({});
      state.open();
      expect(state.isOpen()).toBe(true);
      dispose();
    });
  });

  it("close() sets state to false", () => {
    createRoot((dispose) => {
      const state = createDisclosureState({ defaultOpen: true });
      state.close();
      expect(state.isOpen()).toBe(false);
      dispose();
    });
  });

  it("toggle() flips state", () => {
    createRoot((dispose) => {
      const state = createDisclosureState({});
      state.toggle();
      expect(state.isOpen()).toBe(true);
      state.toggle();
      expect(state.isOpen()).toBe(false);
      dispose();
    });
  });

  it("calls onOpenChange when state changes", () => {
    createRoot((dispose) => {
      const onChange = vi.fn();
      const state = createDisclosureState({ onOpenChange: onChange });
      state.open();
      expect(onChange).toHaveBeenCalledWith(true);
      state.close();
      expect(onChange).toHaveBeenCalledWith(false);
      dispose();
    });
  });

  it("respects controlled open prop", () => {
    createRoot((dispose) => {
      const state = createDisclosureState({ open: true });
      expect(state.isOpen()).toBe(true);
      // Calling close() fires onChange but does not change internal state
      const onChange = vi.fn();
      const controlled = createDisclosureState({ open: true, onOpenChange: onChange });
      controlled.close();
      expect(controlled.isOpen()).toBe(true); // still controlled
      expect(onChange).toHaveBeenCalledWith(false);
      dispose();
    });
  });
});
