import React, { createContext, useContext, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { ScrollView, SectionList, View } from 'react-native';
import dot from 'dot-object';
import useDeepCompareEffect, { useDeepCompareEffectNoCheck } from 'use-deep-compare-effect';
import { useImmer } from 'use-immer';
import { IListSectionContainerProps, IListSectionContainerRef, IListSectionProps } from './ListSection.interface';

const ContextScroll = createContext<any>({} as any);

function useUpdateKey(name): any {
   const { registerItem, unRegisterItem } = useContext(ContextScroll);

   useRef(() => () => unRegisterItem(name));
   return {
      registerItem,
   };
}

export const ListSection = React.forwardRef<IListSectionContainerRef, any>(function ListSection(
   { testID = null, onChange, data, renderItem, renderSectionHeader },
   ref,
) {
   const [items, setItems] = useImmer({});
   const [currentSection, setCurrentSection] = useState<any>();
   const [heightScroll, setHeightScroll] = useState(0);
   const scrollPosY = useRef(0);
   const scrollOffset = useRef(0);
   const itemsArray = useRef([]);
   const ScrollViewRef = useRef<SectionList>();

   useImperativeHandle(
      ref,
      () => ({
         setSection(name) {
            const indexTab = data.findIndex((i) => i.id === name);

            if (indexTab != -1) {
               ScrollViewRef.current.scrollToLocation({
                  sectionIndex: indexTab,
                  itemIndex: 0,
               });

               // Para não atualizar componente dentro de outro componente
               setTimeout(() => {
                  setCurrentSection(items[name]);
               }, 1);
            }
         },
      }),
      [items],
   );

   useEffect(() => {
      scrollPosY.current = 0;
   }, []);

   useDeepCompareEffectNoCheck(() => {
      if (onChange && currentSection) {
         onChange(currentSection.name);
      }
   }, [currentSection, onChange]);

   function registerItem({ name, pos }): void {
      setItems((draft) => {
         dot.set(
            name,
            {
               name,
               pos: pos + scrollPosY.current - scrollOffset.current,
            },
            draft,
         );
      });
   }

   function unRegisterItem(name: string): void {
      setItems((draft) => {
         dot.remove(name, draft);
      });
   }

   useDeepCompareEffect(() => {
      itemsArray.current = Object.values(items);
   }, [items]);

   return (
      <ContextScroll.Provider
         value={{
            registerItem,
            unRegisterItem,
            items: [],
         }}
      >
         <SectionList
            ref={ScrollViewRef}
            testID={testID}
            onLayout={(ev) => {
               scrollOffset.current = ev.nativeEvent.layout.y;
               setHeightScroll(ev.nativeEvent.layout.height);
            }}
            onScroll={(event) => {
               scrollPosY.current = event.nativeEvent.contentOffset.y;
            }}
            onMomentumScrollEnd={() => {
               let currentOffset = 0;
               let selectSection: any;

               itemsArray.current.forEach((item) => {
                  if (scrollPosY.current >= item.pos - heightScroll * 0.2 && item.pos >= currentOffset) {
                     currentOffset = item.pos;
                     selectSection = item;
                  }
               });

               setCurrentSection(() => selectSection);
            }}
            keyExtractor={(item, index) => {
               return item?.id || `card-${index}`;
            }}
            sections={data}
            renderItem={renderItem}
            renderSectionHeader={(section) => (
               <ListHeaderItem name={section.section.id}>{renderSectionHeader(section.section)}</ListHeaderItem>
            )}
         />
      </ContextScroll.Provider>
   );
});

export function ListHeaderItem({ name, children }: any): JSX.Element {
   const viewRef = useRef<any>();

   const { registerItem } = useUpdateKey(name);

   function onLayout(): void {
      viewRef.current.measure((fx, fy, width, height, px, py) => {
         registerItem({
            name,
            pos: py,
         });
      });
   }

   return (
      <View ref={viewRef} onLayout={onLayout}>
         {children}
      </View>
   );
}
