import React, { useEffect } from "react";
import * as R from "ramda";
import { isGroup } from "@applicaster/zapp-react-native-utils/componentsUtils";

import { applyDecorators } from "../../Decorators";

import {
  useCellResolver,
  useComponentResolver,
} from "@applicaster/zapp-react-native-utils/reactHooks/resolvers";

import { riverLogger } from "./logger";
import { tvPluginsWithCellRenderer } from "../../const";
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
import type { BehaviorSubject } from "rxjs";
import { useCallbackActions } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/useCallbackActions";
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";

export type RiverItemType = {
  item: ZappUIComponent;
  index: number;
  isScreenWrappedInContainer: boolean;
  groupId: string | number;
  feed: ZappFeed;
  onLoadFinished: (index: number) => void;
  onLoadFailed: ({ error, index }: { error: Error; index: number }) => void;
  riverId: string;
  getStaticComponentFeed: GeneralContentScreenProps["getStaticComponentFeed"];
  readyToBeDisplayed?: boolean;
  isLast: boolean;
  loadingState: BehaviorSubject<{ index: number }>;
};

function getFeedUrl(feed: ZappFeed, index: number) {
  try {
    const feedUrl = R.path(["entry", index, "content", "src"], feed);

    return (R.contains || R.includes)("fetchData?", feedUrl) ? feedUrl : null;
  } catch (error) {
    return null;
  }
}

const isNextIndex = (index, readyIndex) => {
  return readyIndex + 1 >= index;
};

/**
 * useLoadingState for RiverItemComponent
 * takes currentIndex and loadingState as arguments
 **/
const useLoadingState = (
  currentIndex: number,
  loadingState: RiverItemType["loadingState"]
) => {
  const [readyToBeDisplayed, setReadyToBeDisplayed] = React.useState(
    isNextIndex(currentIndex, loadingState.getValue().index)
  );

  useEffect(() => {
    const subscription = loadingState.subscribe(({ index }) => {
      if (isNextIndex(currentIndex, index)) {
        setReadyToBeDisplayed(true);
      }
    });

    return () => {
      subscription.unsubscribe();
    };
  }, [currentIndex]);

  return readyToBeDisplayed;
};

function RiverItemComponent(props: RiverItemType) {
  const {
    item,
    riverId,
    index,
    groupId,
    feed,
    isScreenWrappedInContainer,
    onLoadFinished,
    onLoadFailed,
    getStaticComponentFeed,
    isLast,
    loadingState,
  } = props;

  const callbackAction = useCallbackActions(item);
  const readyToBeDisplayed = useLoadingState(index, loadingState);

  const feedUrl = getFeedUrl(feed, index);

  const Component = useComponentResolver(
    {
      componentType: item.component_type,
      decorators: applyDecorators,
    },
    []
  );

  let CellRenderer = useCellResolver({ component: item });

  if (tvPluginsWithCellRenderer.includes(item.component_type) && isTV()) {
    riverLogger.warning({
      message:
        "Cell Renderer is not created for this component type by RiverItem",
      data: { component_type: item.component_type },
      jsOnly: true,
    });

    CellRenderer = undefined;
  }

  const isComponentMissing = isNilOrEmpty(Component);

  /**
   * TODO: Move this plugin existence check further up the stack (before ComponentsMap).
   * Filtering items at the list-rendering or data-processing level would prevent
   * mounting RiverItem entirely for missing components.
   */
  React.useEffect(() => {
    if (isComponentMissing) {
      riverLogger.warning({
        message: `Component ${item.component_type} is null - skipping rendering`,
      });

      onLoadFinished(index);
    } else {
      riverLogger.log({
        message: "mounting component",
        data: { item, feedUrl, Component, CellRenderer },
        jsOnly: true,
      });

      if (!CellRenderer && !isGroup(item)) {
        riverLogger.warning({
          message: "Cell Renderer is null - will fallback to default cell",
          data: { item, CellRenderer },
          jsOnly: true,
        });
      }
    }
  }, []);

  if (!readyToBeDisplayed || isComponentMissing) {
    return null;
  }

  return (
    <Component
      CellRenderer={CellRenderer}
      readyToBeDisplayed={readyToBeDisplayed}
      getStaticComponentFeed={getStaticComponentFeed}
      id={item.id}
      riverId={riverId}
      isScreenWrappedInContainer={isScreenWrappedInContainer}
      component={item}
      componentIndex={index}
      onLoadFailed={onLoadFailed}
      onLoadFinished={() => onLoadFinished(index)}
      groupId={groupId}
      feedUrl={feedUrl}
      isLast={isLast}
      callback={callbackAction}
    />
  );
}

export const RiverItem = React.memo<RiverItemType>(
  RiverItemComponent,
  R.equals
);
