import { createRoot, createSignal } from "solid-js";
import { describe, expect, it, vi } from "vitest";
import { createControllableSignal } from "../../src/primitives/create-controllable-signal";

describe("createControllableSignal", () => {
  it("uses defaultValue when value accessor returns undefined (uncontrolled)", () => {
    createRoot((dispose) => {
      const [get] = createControllableSignal({
        value: () => undefined,
        defaultValue: () => false,
      });
      expect(get()).toBe(false);
      dispose();
    });
  });

  it("uses value accessor when provided (controlled)", () => {
    createRoot((dispose) => {
      const [get] = createControllableSignal({
        value: () => true,
        defaultValue: () => false,
      });
      expect(get()).toBe(true);
      dispose();
    });
  });

  it("calls onChange when setter is called in uncontrolled mode", () => {
    createRoot((dispose) => {
      const onChange = vi.fn();
      const [, set] = createControllableSignal({
        value: () => undefined,
        defaultValue: () => false,
        onChange,
      });
      set(true);
      expect(onChange).toHaveBeenCalledWith(true);
      dispose();
    });
  });

  it("updates internal signal when setter called in uncontrolled mode", () => {
    createRoot((dispose) => {
      const [get, set] = createControllableSignal({
        value: () => undefined,
        defaultValue: () => "initial",
      });
      set("updated");
      expect(get()).toBe("updated");
      dispose();
    });
  });

  it("does not update internal signal in controlled mode — external value is source of truth", () => {
    createRoot((dispose) => {
      const [externalValue] = createSignal<string>("controlled");
      const [get, set] = createControllableSignal({
        value: externalValue,
        defaultValue: () => "default",
      });
      set("ignored");
      // Still reflects external value since we're controlled
      expect(get()).toBe("controlled");
      dispose();
    });
  });
});
