import * as React from "react";
import { View } from "react-native";
import { useState, useRef, useEffect } from "react";
import Blocks from "../../components/blocks/blocks";
import InlinedScript from "../../components/inlined-script";
import InlinedStyles from "../../components/inlined-styles";
import { TARGET } from "../../constants/target";
import { getClassPropName } from "../../functions/get-class-prop-name";
import { isEditing } from "../../functions/is-editing";
import { isPreviewing } from "../../functions/is-previewing";
import { getDefaultCanTrack } from "../../helpers/canTrack";
import { userAttributesService } from "../../helpers/user-attributes";
import { filterAttrs } from "../helpers";
import {
  checkShouldRenderVariants,
  DEFAULT_INDEX,
  filterWithCustomTargeting,
  getBlocksToRender,
  getPersonalizationScript,
  getUpdateVisibilityStylesScript,
  SDKS_REQUIRING_RESET_APPROACH,
} from "./helpers";
import type { PersonalizationContainerProps } from "./personalization-container.types";
import { setAttrs } from "../helpers";

function PersonalizationContainer(props: PersonalizationContainerProps) {
  const rootRef = useRef<HTMLDivElement>(null);
  const [userAttributes, setUserAttributes] = useState(() =>
    userAttributesService.getUserAttributes()
  );

  const [scriptStr, setScriptStr] = useState(() =>
    getPersonalizationScript(
      props.variants,
      props.builderBlock?.id || "none",
      props.builderContext?.rootState?.locale as string | undefined
    )
  );

  const [updateVisibilityStylesScript, setUpdateVisibilityStylesScript] =
    useState(() =>
      getUpdateVisibilityStylesScript(
        props.variants,
        props.builderBlock?.id || "none",
        props.builderContext?.rootState?.locale as string | undefined
      )
    );

  const [unsubscribers, setUnsubscribers] = useState(() => []);

  const [shouldRenderVariants, setShouldRenderVariants] = useState(() =>
    checkShouldRenderVariants(
      props.variants,
      getDefaultCanTrack(props.builderContext?.canTrack)
    )
  );

  const [shouldResetVariants, setShouldResetVariants] = useState(() => false);

  function attrs() {
    return {
      ...props.attributes,
      ...{},
      [getClassPropName()]: `builder-personalization-container ${
        props.attributes[getClassPropName()] || ""
      }`,
    };
  }

  function filteredVariants() {
    return (props.variants || []).filter((variant) => {
      return filterWithCustomTargeting(
        {
          ...(props.builderContext?.rootState?.locale
            ? {
                locale: props.builderContext?.rootState?.locale,
              }
            : {}),
          ...(userAttributes as any),
        },
        variant.query,
        variant.startDate,
        variant.endDate
      );
    });
  }

  function blocksToRender() {
    return getBlocksToRender({
      variants: props.variants,
      fallbackBlocks: props.builderBlock?.children,
      isHydrated: shouldResetVariants,
      filteredVariants: filteredVariants(),
      previewingIndex: props.previewingIndex,
    });
  }

  function hideVariantsStyleString() {
    return (props.variants || [])
      .map(
        (_, index) =>
          `div[data-variant-id="${props.builderBlock?.id}-${index}"] { display: none !important; } `
      )
      .join("");
  }

  useEffect(() => {
    setShouldResetVariants(true);
    const unsub = userAttributesService.subscribeOnUserAttributesChange(
      (attrs) => {
        setUserAttributes(attrs);
      },
      {
        fireImmediately: TARGET === "qwik",
      }
    );
    if (!(isEditing() || isPreviewing())) {
      const variant = filteredVariants()[0];
      if (rootRef.current) {
        rootRef.current.dispatchEvent(
          new CustomEvent("builder.variantLoaded", {
            detail: {
              variant: variant || DEFAULT_INDEX,
              content: props.builderContext?.content,
            },
            bubbles: true,
          })
        );
        const observer = new IntersectionObserver((entries) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting && rootRef.current) {
              rootRef.current.dispatchEvent(
                new CustomEvent("builder.variantDisplayed", {
                  detail: {
                    variant: variant || DEFAULT_INDEX,
                    content: props.builderContext?.content,
                  },
                  bubbles: true,
                })
              );
            }
          });
        });
        observer.observe(rootRef.current);
      }
    }
    unsubscribers.push(unsub);
  }, []);

  useEffect(() => {
    return () => {
      unsubscribers.forEach((unsub) => unsub());
    };
  }, []);

  return (
    <View ref={rootRef} {...attrs()}>
      {shouldResetVariants && SDKS_REQUIRING_RESET_APPROACH.includes(TARGET) ? (
        <Blocks
          blocks={blocksToRender().blocks}
          parent={props.builderBlock?.id}
          path={blocksToRender().path}
          context={props.builderContext}
          registeredComponents={props.builderComponents}
          BlocksWrapperProps={{
            ...props.builderContext?.BlocksWrapperProps,
            "data-variant-id": `${props.builderBlock?.id}-${
              blocksToRender().index
            }`,
          }}
        />
      ) : null}
      {(!shouldResetVariants &&
        SDKS_REQUIRING_RESET_APPROACH.includes(TARGET)) ||
      !SDKS_REQUIRING_RESET_APPROACH.includes(TARGET) ? (
        <>
          {shouldRenderVariants ? (
            <>
              <InlinedStyles
                nonce={props.builderContext?.nonce || ""}
                styles={hideVariantsStyleString()}
                id={`variants-styles-${props.builderBlock?.id}`}
              />
              <InlinedScript
                nonce={props.builderContext?.nonce || ""}
                scriptStr={updateVisibilityStylesScript}
                id={`variants-visibility-script-${props.builderBlock?.id}`}
              />
              {props.variants?.map((variant, index) => (
                <Blocks
                  key={`${props.builderBlock?.id}-${index}`}
                  BlocksWrapperProps={{
                    ...props.builderContext?.BlocksWrapperProps,
                    "aria-hidden": true,
                    hidden: true,
                    "data-variant-id": `${props.builderBlock?.id}-${index}`,
                  }}
                  blocks={variant.blocks}
                  parent={props.builderBlock?.id}
                  path={`component.options.variants.${index}.blocks`}
                  context={props.builderContext}
                  registeredComponents={props.builderComponents}
                >
                  <InlinedScript
                    nonce={props.builderContext?.nonce || ""}
                    scriptStr={scriptStr}
                    id={`variants-script-${props.builderBlock?.id}-${index}`}
                  />
                </Blocks>
              ))}
            </>
          ) : null}
          <Blocks
            blocks={blocksToRender().blocks}
            parent={props.builderBlock?.id}
            path={blocksToRender().path}
            context={props.builderContext}
            registeredComponents={props.builderComponents}
            BlocksWrapperProps={{
              ...props.builderContext?.BlocksWrapperProps,
              "data-variant-id": `${props.builderBlock?.id}-${
                blocksToRender().index
              }`,
            }}
          >
            {shouldRenderVariants ? (
              <InlinedScript
                nonce={props.builderContext?.nonce || ""}
                scriptStr={scriptStr}
                id={`variants-script-${props.builderBlock?.id}-${DEFAULT_INDEX}`}
              />
            ) : null}
          </Blocks>
        </>
      ) : null}
    </View>
  );
}

export default PersonalizationContainer;
