import { dynamic } from "@solidjs/web";
import { createMemo, omit } from "solid-js";
import { createChangeEventDetails, REASONS } from "../../internals/change-event-details.jsx";
import { composeRefs, userRef } from "../../internals/compose-refs.jsx";
import { createControlledState } from "../../internals/create-controlled-state.jsx";
import { useFieldRootContext } from "../../internals/field-context.jsx";
import { fieldStateAttrs } from "../../internals/field-state-attrs.jsx";
import { HiddenInput } from "../../internals/hidden-input/hidden-input.jsx";
import { useAriaLabelledBy } from "../../internals/labelable-provider/use-aria-labelled-by.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 { ariaLabelledBy as seedAriaLabelledBy } from "../../internals/seed-aria-attr.jsx";
import { useButton } from "../../internals/use-button/use-button.jsx";
import { useFieldControlValidation } from "../../internals/use-field-control-validation/use-field-control-validation.jsx";
import { createSwitch } from "../create-switch.jsx";
import { SwitchRootContext } from "../switch-root-context.jsx";

/** The reason carried on every `onCheckedChange` event details bag. */

/** Shape of the `onCheckedChange` event details bag. */

/**
 * Represents the switch itself. Renders a `<button role="switch">` (or
 * `as` override) and a visually-hidden `<input type="checkbox">` for form
 * submission.
 *
 * Solid 2.0-native rewire (§1 wave 1): replaces `renderElement` with
 * `dynamic(() => props.as ?? "button")` and threads
 * `createSwitch().trigger()` (carrying ARIA + checked/disabled/readonly
 * data-attrs) plus useButton + field-validation + field-state data-attrs
 * through `mergeRootProps`. Field-state attrs (`data-valid`,
 * `data-touched`, `data-dirty`, `data-filled`, `data-focused`) are
 * emitted via inline getters that read from `state()` so they stay
 * reactive — the slot factory itself doesn't carry these.
 */
export function SwitchRoot(props) {
  const field = useFieldRootContext();
  const disabled = () => field.disabled() || props.disabled === true;
  const readOnly = () => readOption(props.readOnly) === true;
  const required = () => readOption(props.required) === true;
  const nativeButton = () => props.nativeButton ?? true;
  const name = () => field.name() ?? props.name;

  // Controlled / uncontrolled checked state (Base UI `checked` /
  // `defaultChecked` contract, mirroring React's `useControlled` in
  // `SwitchRoot`): the `checked` prop wins while its resolved value is
  // defined; otherwise an internal signal (seeded once from
  // `defaultChecked`) backs the state.
  const [resolvedChecked, setUncontrolledChecked] = createControlledState({
    controlled: () => {
      const controlled = readOption(props.checked);
      return controlled === undefined ? undefined : Boolean(controlled);
    },
    default: () => readOption(props.defaultChecked),
    fallback: false,
    name: "<Switch.Root>",
    state: "checked"
  });
  const c = createSwitch({
    checked: resolvedChecked,
    disabled,
    readOnly,
    required,
    onCheckedChange: (next, event) => {
      const details = createChangeEventDetails(REASONS.none, event);
      // Base UI change flow: fire the consumer callback first, honor
      // `details.cancel()`, then write the uncontrolled state (a no-op
      // for reads while the `checked` prop is controlled).
      props.onCheckedChange?.(next, details);
      if (details.isCanceled) {
        event.preventDefault();
        return;
      }
      setUncontrolledChecked(next);
    }
  });
  const checkedAccessor = c.checked;
  const {
    props: buttonProps,
    ref: buttonRef
  } = useButton({
    disabled,
    native: nativeButton
  });
  const validation = useFieldControlValidation({
    value: checkedAccessor,
    id: () => typeof props.id === "string" ? props.id : undefined,
    controlRef: field.validation.inputRef,
    getValue: checkedAccessor
  });
  const state = createMemo(() => ({
    ...field.state(),
    checked: checkedAccessor(),
    disabled: disabled(),
    readOnly: readOnly(),
    required: required()
  }));
  const contextValue = {
    checked: checkedAccessor,
    disabled,
    readOnly,
    required,
    state
  };
  function handleHiddenInputChange(event) {
    if (readOnly()) {
      event.preventDefault();
      return;
    }
    c.setChecked(event.currentTarget.checked, event, "trigger-press");
  }

  // Field-state data-attrs not carried by `c.trigger()`. The slot factory
  // already emits data-checked/unchecked/disabled/readonly/required; here
  // we add validity + interaction attrs via the shared helper.
  const switchFieldAttrs = fieldStateAttrs(state);
  const ariaLabelledBy = useAriaLabelledBy(() => {
    const v = props["aria-labelledby"];
    return typeof v === "string" ? v : undefined;
  });

  // Root-level event handlers + onBlur/onFocus field wiring. The toggle
  // onClick comes from c.trigger(); we layer onBlur/onFocus separately.
  const fieldEventHandlers = {
    onBlur() {
      if (disabled()) return;
      field.setTouched(true);
      field.setFocused(false);
      if (field.validationMode() === "onBlur") {
        void validation.commit(checkedAccessor());
      }
    },
    onFocus() {
      if (disabled()) return;
      field.setFocused(true);
    }
  };
  const userStyling = resolveClassStyle(props, () => state());
  const userProps = omit(props, "class", "style", "attrs", "as", "checked", "children", "defaultChecked", "disabled", "form", "name", "nativeButton", "onCheckedChange", "readOnly", "required", "uncheckedValue", "value");

  // Compose: useButton ∘ field-validation ∘ aria-labelledby ∘ c.trigger() ∘
  // fieldStateAttrs ∘ fieldEventHandlers ∘ userProps. Event handlers chain
  // in declaration order, gated by defaultPrevented.
  const labelledByBag = seedAriaLabelledBy(ariaLabelledBy) ?? {};
  const validationBag = validation.getAriaInvalidProps() ?? {};
  const styledUserProps = mergeRootProps(userStyling, userProps);
  let merged = mergeRootProps(buttonProps, validationBag);
  merged = mergeRootProps(merged, labelledByBag);
  merged = mergeRootProps(merged, c.trigger());
  merged = mergeRootProps(merged, switchFieldAttrs);
  merged = mergeRootProps(merged, fieldEventHandlers);
  merged = mergeRootProps(merged, styledUserProps);
  const Tag = dynamic(() => props.as ?? "button");
  const button = <Tag {...merged} ref={composeRefs(buttonRef, userRef(props))}>
			<SwitchRootContext value={contextValue}>
				{props.children}
			</SwitchRootContext>
		</Tag>;
  return <>
			{button}
			<HiddenInput type="checkbox" checked={checkedAccessor()} disabled={disabled()} form={props.form} name={name()} required={required()} value={props.value} tabindex={-1} aria-hidden="true" onChange={handleHiddenInputChange} />
			{!checkedAccessor() && name() && props.uncheckedValue !== undefined ? <input type="hidden" form={props.form} name={name()} value={props.uncheckedValue} /> : null}
		</>;
}
//# sourceMappingURL=switch-root.jsx.map
