import { dynamic } from "@solidjs/web";
import { omit } from "solid-js";
import { createChangeEventDetails, REASONS } from "../internals/change-event-details.jsx";
import { composeRefs, userRef } from "../internals/compose-refs.jsx";
import { useCompositeRootContext } from "../internals/composite/composite-context.jsx";
import { useCompositeListItem } from "../internals/composite/composite-list.jsx";
import { createControlledState } from "../internals/create-controlled-state.jsx";
import { readOption } from "../internals/maybe-accessor.jsx";
import { mergeRootProps } from "../internals/merge-root-props.jsx";
import { resolveClassStyle } from "../internals/resolve-class-style.jsx";
import { useButton } from "../internals/use-button/use-button.jsx";
import { useToggleGroupContext } from "../toggle-group/toggle-group-context.jsx";
import { createToggle } from "./create-toggle.jsx";

/**
 * The reason string attached to every `onPressedChange` event details object.
 * Matches Base UI React's `Toggle.ChangeEventReason`.
 */

/**
 * Shape of the details bag handed to `onPressedChange`.
 */

/**
 * The state object exposed through `data-*` projection and the `class` /
 * `style` callback surfaces.
 */

/**
 * A two-state button that can be on or off. Renders a `<button>` element
 * (or `as` override).
 *
 * Solid 2.0-native rewire (§1 wave 1): replaces `renderElement` with
 * `dynamic(() => props.as ?? "button")` and threads
 * `createToggle().trigger()` + the `useButton` reactive bag + composite-
 * list focus/tabIndex through `mergeRootProps`. The slot factory now
 * carries data-pressed/data-disabled/aria-pressed.
 */
export function Toggle(props) {
  const group = useToggleGroupContext();
  const inGroup = group?.present === true;
  const ownDisabled = () => {
    if (props.disabled) return true;
    if (inGroup) return group?.disabled() === true;
    return false;
  };
  const nativeButton = () => props.nativeButton ?? true;

  // Controlled / uncontrolled pressed state (Base UI `pressed` /
  // `defaultPressed` contract, mirroring React's `useControlled` in
  // `Toggle`): inside a group the pressed state is always derived from the
  // group's value array (always controlled, `default` is `undefined`);
  // standalone, the `pressed` prop wins while its resolved value is
  // defined, else an internal signal seeded once from `defaultPressed`.
  const [resolvedPressed, setUncontrolledPressed] = createControlledState({
    controlled: () => {
      if (inGroup) {
        const v = props.value;
        if (v == null || v === "") return false;
        return group?.value().includes(v) ?? false;
      }
      const controlled = readOption(props.pressed);
      return controlled === undefined ? undefined : Boolean(controlled);
    },
    default: () => inGroup ? undefined : readOption(props.defaultPressed),
    fallback: false,
    name: "<Toggle>",
    state: "pressed"
  });
  const c = createToggle({
    pressed: resolvedPressed,
    disabled: ownDisabled,
    onPressedChange: (next, event) => {
      const details = createChangeEventDetails(REASONS.none, event);

      // Base UI change flow (React `Toggle.onClick`): route the change
      // through the group first (the group fires its own onValueChange
      // against the same details bag), then the toggle's own
      // onPressedChange, then honor `details.cancel()`, then write the
      // uncontrolled state (a no-op for reads while controlled / in a
      // group).
      if (inGroup) {
        const v = props.value;
        if (v != null && v !== "") {
          group?.setGroupValue(v, next, details);
        }
      }
      props.onPressedChange?.(next, details);
      if (details.isCanceled) {
        event.preventDefault();
        return;
      }
      setUncontrolledPressed(next);
    }
  });
  const {
    props: buttonProps,
    ref: buttonRef
  } = useButton({
    disabled: c.disabled,
    native: nativeButton,
    composite: () => inGroup
  });
  const {
    ref: listItemRef,
    index: itemIndex
  } = useCompositeListItem({});
  const rootContext = useCompositeRootContext(true);
  const groupTabIndex = () => {
    if (!rootContext) return undefined;
    return rootContext.highlightedIndex() === itemIndex() ? 0 : -1;
  };
  const onGroupFocus = () => {
    if (!rootContext) return;
    const i = itemIndex();
    if (i >= 0) rootContext.onHighlightedIndexChange(i);
  };

  // Composite/group concerns: tabIndex + focus handler. Plus useButton's
  // reactive bag. These form the "internal" side; c.trigger() is layered
  // next so the toggle's onClick composes correctly with useButton's
  // disabled-suppression.
  const compositeBag = {
    get tabIndex() {
      return groupTabIndex();
    },
    onFocus: onGroupFocus
  };
  const userStyling = resolveClassStyle(props, () => ({
    pressed: c.pressed(),
    disabled: c.disabled()
  }));
  const userProps = omit(props, "class", "style", "attrs", "as", "defaultPressed", "disabled", "form", "nativeButton", "onPressedChange", "pressed", "type", "value");

  // Compose, left-to-right wins on the right per mergeRootProps:
  //   compositeBag ∘ buttonProps ∘ c.trigger() ∘ userProps
  // Event handlers chain in declaration order, gated by defaultPrevented
  // (so useButton's disabled check fires before the toggle onClick).
  const step1 = mergeRootProps(compositeBag, buttonProps);
  const triggerBag = c.trigger();
  const step2 = mergeRootProps(step1, triggerBag);
  const styledUserProps = mergeRootProps(userStyling, userProps);
  const merged = mergeRootProps(step2, styledUserProps);
  const Tag = dynamic(() => props.as ?? "button");
  return <Tag {...merged} ref={composeRefs(buttonRef, listItemRef, userRef(props))} />;
}
//# sourceMappingURL=toggle.jsx.map
