'use strict';

Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });

const react = require('react');

/**
 * Creates a React component that renders a remote DOM element. This component will pass
 * through all the props from the React component to the remote DOM element, and will
 * convert any props that are React elements into a `remote-fragment` element with a `slot`
 * attribute that matches the prop name.
 *
 * @param tag The name of the remote DOM element to render
 * @param Element The constructor for the remote DOM element to render. If not provided,
 * the constructor will be looked up using `customElements.get(tag)`.
 */
function createRemoteComponent(tag, Element = customElements.get(tag), {
  slotProps = true,
  eventProps = {}
} = {}) {
  const normalizeSlotProps = Boolean(slotProps);
  const slotPropWrapperOption = (typeof slotProps === 'object' ? slotProps.wrapper : undefined) ?? true;
  const slotPropWrapper = typeof slotPropWrapperOption === 'string' ? slotPropWrapperOption : slotPropWrapperOption ? 'remote-fragment' : false;

  // @ts-expect-error I can’t make the types work :/
  const RemoteComponent = /*#__PURE__*/react.forwardRef(function RemoteComponent(props, ref) {
    const internalRef = react.useRef();
    const lastRemotePropertiesRef = react.useRef();
    const remoteProperties = {};
    const children = toChildren(props.children);
    for (const prop in props) {
      const propValue = props[prop];
      if (prop === 'slot') {
        remoteProperties.slot = propValue;
        continue;
      }
      if (normalizeSlotProps && Element.remoteSlotDefinitions.has(prop) && /*#__PURE__*/react.isValidElement(propValue)) {
        if (!slotPropWrapper) {
          children.push(/*#__PURE__*/react.cloneElement(propValue, {
            slot: prop
          }));
        } else {
          children.push(/*#__PURE__*/react.createElement(slotPropWrapper, {
            slot: prop
          }, propValue));
        }
        continue;
      }
      remoteProperties[prop] = propValue;
    }
    react.useLayoutEffect(() => {
      const element = internalRef.current;
      if (element == null) return;
      for (const prop in remoteProperties) {
        if (prop === 'children') continue;
        const oldValue = lastRemotePropertiesRef.current?.[prop];
        const newValue = remoteProperties[prop];
        if (oldValue === newValue) continue;
        const eventProp = eventProps[prop];
        if (eventProp) {
          const eventName = eventProp.event;
          if (oldValue) element.removeEventListener(eventName, oldValue);
          if (newValue) element.addEventListener(eventName, newValue);
          continue;
        }
        if (prop in element) {
          element[prop] = remoteProperties[prop];
          continue;
        }
        if (newValue == null) {
          element.removeAttribute(prop);
        } else {
          element.setAttribute(prop, String(newValue));
        }
      }
      lastRemotePropertiesRef.current = remoteProperties;
    });
    return /*#__PURE__*/react.createElement(tag, {
      ref: refValue => {
        internalRef.current = refValue;
        if (typeof ref === 'function') ref(refValue);else if (ref != null) ref.current = refValue;
      }
    }, ...children);
  });
  RemoteComponent.displayName = `RemoteComponent(${tag})`;
  return RemoteComponent;
}

// Simple version of React.Children.toArray()
function toChildren(value) {
  if (value == null) return [];
  if (Array.isArray(value)) return [...value];
  return [value];
}

exports.createRemoteComponent = createRemoteComponent;
