import { getKeys } from "../theme/utils/type-helpers";
import { useTheme } from "./useTheme";
import { MOTI_PROPS, checkKeyAvailability, composeStyleProps } from "./utils/utils";
import { useColorScheme } from "./useColorScheme";
import { useResponsiveProp } from "./useResponsiveProp";
import { useStyleProps } from "./useStyleProps";
import { boxStyleFunctions } from "../theme/src/style-functions";
import { removeUndefined } from "../theme/utils/utils";
import { useMemo } from "react";
import _ from "lodash";

/**
 * useMolecularComponentConfig is a custom hook used to convert a molecular component style config to the appropriate React Native styles.
 * It takes the benefits of the useAtomicComponentConfig hook to the next level, allowing you to create complex components by combining different atomic components while still maintaining the ease of the styling through a component style config.
 *
 * @param themeComponentKey Name of the component in PearlTheme.components who's config needs to be used
 * @param receivedProps Raw props passed to the component where the hook is being used
 * @param sizeAndVariantProps Custom size and variant configuration to use
 * @param colorScheme Active color scheme of the component
 * @param styleFunctions List of style functions to use for computing the received style props
 * @param partForOverridenStyleProps The part where the style props passed to the component instance should be reflected. If undefined, the style props are passed to the first part as specified in the config
 * @param partForOverridenNativeProps The part where other native props (non-style props) passed to the component instance should be reflected. If undefined, the native props are passed to the first part as specified in the config
 * @param partForOverridenAnimationProps The part where animation props passed to the component instance should be reflected. If undefined, the animation props are passed to the first part as specified in the config
 * @returns
 */
export const useMolecularComponentConfig = (componentName, receivedProps, sizeAndVariantProps = {
  size: undefined,
  variant: undefined
}, colorScheme = "primary", styleFunctions = boxStyleFunctions, partForOverridenStyleProps = undefined, partForOverridenNativeProps = undefined, partForOverridenAnimationProps = undefined) => {
  const {
    theme
  } = useTheme();
  checkKeyAvailability(componentName, theme.components, "theme.components");

  // User overriden props
  const buildStyleProperties = useMemo(() => composeStyleProps(styleFunctions), [styleFunctions]);
  const overridenStyleProps = useMemo(() => _.pick(receivedProps, buildStyleProperties.properties), [receivedProps, buildStyleProperties]);
  const overridenAnimationProps = useMemo(() => _.pick(receivedProps, MOTI_PROPS), [receivedProps]);
  const overridenNativeProps = useMemo(() => _.omit(receivedProps, [...MOTI_PROPS, "style", ...buildStyleProperties.properties]), [receivedProps, buildStyleProperties]);
  const overridenProps = useStyleProps(receivedProps, styleFunctions);

  // Responsive Size and Variant
  const sizeForCurrentScreenSize = useResponsiveProp(sizeAndVariantProps.size);
  const variantForCurrentScreenSize = useResponsiveProp(sizeAndVariantProps.variant);
  const componentStyleConfig = useMemo(() => theme.components[componentName], [theme, componentName]);
  const activeSizeAndVariantConfig = {};
  const defaultComponentConfig = useMemo(() => componentStyleConfig["defaults"], [componentStyleConfig]);
  if (defaultComponentConfig) {
    if (defaultComponentConfig.hasOwnProperty("size")) {
      activeSizeAndVariantConfig.size = sizeForCurrentScreenSize ? sizeForCurrentScreenSize : defaultComponentConfig.size;
    }
    if (defaultComponentConfig.hasOwnProperty("variant")) {
      activeSizeAndVariantConfig.variant = variantForCurrentScreenSize ? variantForCurrentScreenSize : defaultComponentConfig.variant;
    }
  }
  if (!componentStyleConfig.hasOwnProperty("parts")) {
    throw new Error(`Key 'parts' does not exist in theme.components["${componentName}"]`);
  }
  let finalComponentProps = {};

  // Assign overriden props to the root
  if (!partForOverridenStyleProps) {
    finalComponentProps = {
      ...finalComponentProps,
      ...removeUndefined(overridenStyleProps),
      style: receivedProps.style
    };
  }

  // Native props by default go to the 'root' part
  if (!partForOverridenNativeProps) {
    finalComponentProps = {
      ...finalComponentProps,
      ...removeUndefined(overridenNativeProps)
    };
  }

  // Native props by default go to the 'root' part
  if (!partForOverridenAnimationProps) {
    finalComponentProps = {
      ...finalComponentProps,
      ...removeUndefined(overridenAnimationProps)
    };
  }
  componentStyleConfig.parts.forEach(part => {
    const componentTypeStyles = getKeys(activeSizeAndVariantConfig).reduce((style, currProp) => {
      let activeSizeAndVariantStyles;
      if (currProp === "size") {
        checkKeyAvailability("sizes", componentStyleConfig, `theme.components['${String(componentName)}']`);
        checkKeyAvailability(activeSizeAndVariantConfig["size"], componentStyleConfig.sizes, `theme.components['${String(componentName)}']['sizes']`);
        let partConfig = componentStyleConfig.sizes[activeSizeAndVariantConfig[currProp]][part];
        if (typeof partConfig === "function") partConfig = partConfig(activeSizeAndVariantConfig.variant, colorScheme);
        activeSizeAndVariantStyles = partConfig;
      } else {
        checkKeyAvailability("variants", componentStyleConfig, `theme.components['${String(componentName)}']`);
        checkKeyAvailability(activeSizeAndVariantConfig["variant"], componentStyleConfig.variants, `theme.components['${String(componentName)}']['variants']`);
        let partConfig = componentStyleConfig.variants[activeSizeAndVariantConfig[currProp]][part];
        if (typeof partConfig === "function") partConfig = partConfig(activeSizeAndVariantConfig.size, colorScheme);
        activeSizeAndVariantStyles = partConfig;
      }
      if (style) {
        return {
          ...style,
          ...removeUndefined(activeSizeAndVariantStyles)
        };
      }
      return activeSizeAndVariantStyles;
    }, null);
    let currentComponentPartProps = {
      ...((componentStyleConfig["baseStyle"] || {})[part] || {}),
      ...removeUndefined(componentTypeStyles)
    };
    if (partForOverridenStyleProps && part === partForOverridenStyleProps) {
      currentComponentPartProps = {
        ...currentComponentPartProps,
        ...removeUndefined(overridenStyleProps),
        style: {
          ...currentComponentPartProps.style,
          ...removeUndefined(overridenProps.style)
        }
      };
    }
    if (partForOverridenNativeProps && part === partForOverridenNativeProps) {
      currentComponentPartProps = {
        ...currentComponentPartProps,
        ...removeUndefined(overridenNativeProps)
      };
    }
    if (partForOverridenAnimationProps && part === partForOverridenAnimationProps) {
      currentComponentPartProps = {
        ...currentComponentPartProps,
        ...removeUndefined(overridenAnimationProps)
      };
    }

    // For child references
    if (overridenProps.atoms && overridenProps.atoms[part]) currentComponentPartProps = {
      ...currentComponentPartProps,
      ...removeUndefined(overridenProps.atoms[part])
    };
    finalComponentProps = {
      ...finalComponentProps,
      atoms: {
        ...finalComponentProps.atoms,
        [part]: currentComponentPartProps
      }
    };
  });
  finalComponentProps = useColorScheme(colorScheme, finalComponentProps);
  return finalComponentProps;
};
//# sourceMappingURL=useMolecularComponentConfig.js.map