import { createContext, useContext, mergeProps, createMemo, createSignal, createEffect, splitProps } from 'solid-js';
import { Dynamic } from 'solid-js/web';

function isFunction(value) {
  // eslint-disable-next-line eqeqeq
  return !!(value && {}.toString.call(value) == '[object Function]');
}

function composeRefs(ownRef, ...props) {
  return ref => {
    ownRef.current = ref;

    for (const prop of props) {
      if (!prop.ref) continue;
      if (isFunction(prop.ref)) prop.ref(ref);
    }
  };
}

let id = 0;

function createId(propsId) {
  if (propsId) return String(propsId);
  return String(id++);
}

const DisclosureContext = /*#__PURE__*/createContext({});
function useDisclosureContext() {
  return useContext(DisclosureContext);
}

var isProduction = process.env.NODE_ENV === 'production';

function warning(condition, message) {
  if (!isProduction) {
    if (condition) {
      return;
    }

    var text = "Warning: " + message;

    if (typeof console !== 'undefined') {
      console.warn(text);
    }

    try {
      throw Error(text);
    } catch (x) {}
  }
}

function Disclosure(props) {
  props = mergeProps({
    defaultOpen: false
  }, props);

  const isControlled = () => props.open != null;

  const id = createMemo(() => createId(props.id) || 'disclosure');

  const panelId = () => `panel---${id()}`;

  const [isOpen, setIsOpen] = createSignal(isControlled() ? props.open : props.defaultOpen);

  if (process.env.NODE_ENV !== "production") {
    const wasControlled = isControlled();
    createEffect(() => {
      process.env.NODE_ENV !== "production" ? warning(!(isControlled() && !wasControlled || !isControlled() && wasControlled), 'Disclosure is changing from controlled to uncontrolled. Disclosure should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled Disclosure for the lifetime of the component. Check the `open` prop being passed in.') : void 0;
    });
  }

  function onSelect() {
    var _a;

    (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props);

    if (!isControlled()) {
      setIsOpen(isOpen => !isOpen);
    }
  }

  const context = {
    disclosureId: id,
    onSelect,
    open: isOpen,
    panelId
  };

  if (isControlled() && props.open !== isOpen()) {
    /*
     * If the component is controlled, we'll sync internal state with the
     * controlled state
     */
    setIsOpen(props.open);
  }

  return <DisclosureContext.Provider value={context}>
      {props.children}
    </DisclosureContext.Provider>;
}

function DisclosureButton(props) {
  props = mergeProps({
    as: 'button'
  }, props);
  const [local, others] = splitProps(props, ['as', 'children', 'ref']);
  const button = {};
  const context = useContext(DisclosureContext);

  function handleClick(event) {
    event.preventDefault();
    button.current && button.current.focus();
    context.onSelect();
  }

  return <Dynamic aria-controls={context.panelId()} aria-expanded={context.open()} id={`button---${context.disclosureId()}`} {...others} component={local.as} onClick={handleClick} ref={composeRefs(button, props)} data-reach-disclosure-button="" data-state={context.open() ? 'open' : 'collapsed'}>
      {local.children}
    </Dynamic>;
}

function DisclosurePanel(props) {
  props = mergeProps({
    as: 'div'
  }, props);
  const [local, others] = splitProps(props, ['as', 'children', 'ref']);
  const context = useContext(DisclosureContext);
  return <Dynamic hidden={!context.open()} {...others} ref={props.ref} component={local.as} data-reach-disclosure-panel="" data-state={context.open() ? 'open' : 'collapsed'} id={context.panelId()}>
      {local.children}
    </Dynamic>;
}

export { Disclosure, DisclosureButton, DisclosurePanel, useDisclosureContext };
