import { type Accessor, createSignal } from "solid-js";

export interface CreateControllableSignalOptions<T> {
  /** Returns the controlled value, or undefined if uncontrolled. */
  value: Accessor<T | undefined>;
  /** Default value used when uncontrolled. Only read once at creation time — not reactive after mount. */
  defaultValue: Accessor<T>;
  /** Called whenever the value changes (both modes). */
  onChange?: ((value: T) => void) | undefined;
}

/**
 * Handles controlled vs uncontrolled state for any stateful component.
 * When `value()` is not undefined, the component is controlled — the external
 * value is the source of truth. Otherwise, an internal signal manages state.
 */
export function createControllableSignal<T>(
  options: CreateControllableSignalOptions<T>,
): [Accessor<T>, (value: T) => void] {
  const [internalValue, setInternalValue] = createSignal<T>(options.defaultValue());

  const get: Accessor<T> = () => {
    const controlled = options.value();
    if (controlled !== undefined) return controlled;
    return internalValue();
  };

  const set = (value: T) => {
    const isControlled = options.value() !== undefined;
    if (!isControlled) {
      // Use functional form so SolidJS does not interpret T-as-function as an updater.
      setInternalValue(() => value);
    }
    options.onChange?.(value);
  };

  return [get, set];
}
