import React, { useCallback, useMemo, useRef } from "react";
import { FlatList, View, ImageBackground } from "react-native";
import { Gutter } from "../Gutter";
import * as R from "ramda";
import { useConfiguration } from "@applicaster/zapp-react-native-utils/reactHooks/configuration";
import { FocusableGroup } from "@applicaster/zapp-react-native-ui-components/Components/FocusableGroup";
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";

import Tab from "./Tab";
import { getStyles } from "./styles";
import { forceFocusableFocus } from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
import {
  getId,
  scrollToSelectedIndex as scrollToSelectedIndexFn,
  generateFocusableId,
  applyFontConfig,
} from "./utils";
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";

const VIEW_POSITION = 0.5;

const TabsComponent = ({
  entry,
  groupId,
  id,
  style,
  selectedEntryIndex,
  setSelectedEntry,
}: TabsProps & Partial<TabsSelectionContextType>) => {
  const configuration = useConfiguration();
  const config = applyFontConfig(configuration);
  const styles = useMemo(() => getStyles(config), [config]);

  const {
    tab_bar_gutter: horizontalGutter,
    tab_bar_background_image: bgImage,
    component_padding_left: componentPaddingLeft,
    component_padding_right: componentPaddingRight,
  } = config;

  const {
    tabs,
    tabsWrapper,
    tabsBackground,
    tabsListWrapper,
    tabsListContentContainer,
    tabsFocusableGroup,
  } = styles;

  const flatListRef = useRef(null);

  const entryLength = R.length(entry);

  const scrollToSelectedIndex = useMemo(() => {
    return scrollToSelectedIndexFn(flatListRef, config, entryLength);
  }, [config]);

  const forceFocusOnItem = (itemId) => {
    try {
      const generatedItemId = generateFocusableId(itemId);
      forceFocusableFocus(id as string, generatedItemId);
    } catch (e) {
      // eslint-disable-next-line no-console
      console.warn("Failed to force focus on previously selected item", {
        error: e,
        itemId,
      });
    }
  };

  const onListElementFocus = useCallback(
    (index) => {
      scrollToSelectedIndex(index, VIEW_POSITION);
    },
    [scrollToSelectedIndex]
  );

  const renderItem = useCallback(
    ({ item, index }) => {
      const itemId = generateFocusableId(getId(item));

      const isSelected = R.equals(index, selectedEntryIndex);

      const isLast = R.equals(index, entryLength - 1);
      const isFirst = R.equals(index, 0);

      const style = {
        paddingLeft: isFirst ? Number(componentPaddingLeft) : 0,
        paddingRight: isLast ? Number(componentPaddingRight) : 0,
        marginLeft: isFirst ? -Number(componentPaddingLeft) : 0,
        marginRight: isLast ? -Number(componentPaddingRight) : 0,
      };

      return (
        <Focusable
          groupId={id}
          id={itemId}
          testID={itemId}
          preferredFocus={isSelected}
          onFocus={() => onListElementFocus(index)}
          onPress={() => setSelectedEntry && setSelectedEntry(item)}
          style={style}
        >
          {(focused) => (
            <Tab
              id={itemId}
              item={item}
              focused={focused}
              selected={isSelected}
              styles={styles}
              config={config}
            />
          )}
        </Focusable>
      );
    },
    [onListElementFocus, id, selectedEntryIndex]
  );

  const renderGutter = useCallback(
    () => <Gutter width={horizontalGutter} />,
    [horizontalGutter]
  );

  const onLayoutChange = useCallback(() => {
    forceFocusOnItem(getId(entry[selectedEntryIndex || 0]));
    scrollToSelectedIndex(selectedEntryIndex, VIEW_POSITION);
  }, [scrollToSelectedIndex, selectedEntryIndex, entry]);

  return (
    <View style={[tabsWrapper, style]}>
      <FocusableGroup
        groupId={groupId}
        id={id}
        preferredFocus
        shouldUsePreferredFocus
        isWithMemory={false}
        style={tabsFocusableGroup as {}}
      >
        <View style={tabs}>
          <ImageBackground
            style={tabsBackground}
            source={{ uri: !isEmptyOrNil(bgImage) ? bgImage : undefined }}
          >
            <FlatList
              horizontal
              onLayout={onLayoutChange}
              contentContainerStyle={tabsListContentContainer}
              scrollEnabled={false}
              showsVerticalScrollIndicator={false}
              showsHorizontalScrollIndicator={false}
              ref={flatListRef}
              onScrollToIndexFailed={noop}
              keyExtractor={getId}
              initialScrollIndex={selectedEntryIndex}
              extraData={selectedEntryIndex}
              data={entry}
              renderItem={renderItem}
              ItemSeparatorComponent={renderGutter}
              style={tabsListWrapper}
              initialNumToRender={entryLength}
              maxToRenderPerBatch={entryLength}
              removeClippedSubviews={false}
            />
          </ImageBackground>
        </View>
      </FocusableGroup>
    </View>
  );
};

export const Tabs = React.memo(TabsComponent);
