import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { useEventListener } from '@devesharp/react-hooks';
import { CardListingContainer } from './CardListingContainer';
import { FiltersContainer } from './FiltersContainer';
import { IPageListingProps, IPageListingChildrenProps, IPageListing } from './PageListing.interface';
import { PageListingContext } from './PageListingContext';

export const PageListingContainer: React.FunctionComponent<IPageListingProps> = function PageListing(props) {
   const { viewList, data = {}, children } = props;

   /**
    * Mostrar/Esconder modal de filtros na versão mobile
    */
   const [filterMobileOpen, setFilterMobileOpen] = useState<boolean>(false);

   /**
    *  Filtro temporário para não atualizar enquanto estiver no modal mobile
    */
   const [filtersDebounce, setFiltersDebounce] = useState(viewList.filters);

   const listingElRef = useRef<any>();

   /**
    * Move scroll para o topo quando muda página
    */
   useEffect(
      () =>
         viewList.registerOnSearch(() => {
            if (listingElRef.current) {
               listingElRef.current.scrollTop = 0;
            }
         }),
      [],
   );

   /**
    * Atualizar filtros
    */
   const updateFilters = useCallback(function updateFilters(data: any) {
      viewList.setFilters(() => data);
   }, []);

   /**
    * Limpar todos os filtros
    */
   const clearFilters = useCallback(function clearFilters() {
      // remove hash filter se houver
      if (window.location.hash === '#filter') {
         if (viewList.history) {
            viewList.history.replace({
               search: window.location.search,
               hash: '',
            });
         } else {
            window.location.replace('');
         }
      }

      viewList.setFilters(() => ({}));

      // fecha mobile filter
      setFilterMobileOpen(false);
   }, []);

   /**
    * Mudar página
    */
   const setPage = useCallback((page) => {
      viewList.setPage(page);
   }, []);

   /**
    * Atualizar filtro debounce
    */
   const updateFiltersDebounce = useCallback(function updateFiltersDbebounce(data: any) {
      setFiltersDebounce(() => data);
   }, []);

   /**
    * Aplicar alterações do filtro debounce no filtro principal
    */
   const applyFiltersDebounce = useCallback(
      function applyFilters() {
         // remove hash filter se houver
         if (window.location.hash === '#filter') {
            if (viewList.history) {
               viewList.history.replace({
                  search: window.location.search,
                  hash: '',
               });
            } else {
               window.location.replace('');
            }
         }

         // atualiza filtros
         viewList.setFilters(() => filtersDebounce, { replaceUrl: true });

         // fecha mobile filter
         setFilterMobileOpen(false);
      },
      [filtersDebounce],
   );

   /**
    * Mostrar modal de filtros mobile
    */
   const openFilters = useCallback(() => {
      setFilterMobileOpen(true);
      if (viewList.history) {
         viewList.history.push({
            search: window.location.search,
            hash: '#filter',
         });
      } else {
         window.location.hash = 'filter';
      }
   }, []);

   /**
    * Esconder modal de filtros mobile
    */
   const closeFilters = useCallback(() => {
      setFilterMobileOpen(false);

      if (window.location.hash === '#filter') {
         if (viewList.history) {
            viewList.history.goBack();
         } else {
            window.history.back();
         }
      }
   }, []);

   /**
    * Remove caso tenho a hash #filter (abrir modal mobile)
    */
   useEffect(() => {
      if (window.location.hash === '#filter') {
         if (viewList.history) {
            viewList.history.replace({
               search: window.location.search,
               hash: '',
            });
         } else {
            window.location.replace('');
         }
      }
   }, []);

   /**
    * Mostrar/Esconde mobile filter caso a url mude
    */
   useEventListener('hashchange', function hashchange() {
      if (window.location.hash === '#filter') {
         setFilterMobileOpen(true);
      } else {
         setFilterMobileOpen(false);
      }
   });

   /*
    |--------------------------------------------------------------------------
    | Informações da página
    |--------------------------------------------------------------------------
    */

   // Página atual
   // const currentPage = viewList.filters.page ?? 1;
   const currentPage = (viewList.filters.offset ?? 0) / viewList.limit + 1;

   // Offset inicial
   let pageCountStart = (currentPage - 1) * viewList.limit + 1;
   pageCountStart = viewList.resourcesTotal ? pageCountStart : 0;

   // Offset final
   let pageCountEnd = (currentPage - 1) * viewList.limit + viewList.limit;
   pageCountEnd = pageCountEnd > viewList.resourcesTotal ? viewList.resourcesTotal : pageCountEnd;

   // Se deve mostrar resultados skeletons
   const showCardsSkeleton = viewList.searching || viewList.loading;

   // Se deve mostrar resultados
   const showCards = viewList.started && !viewList.searching;

   return (
      <PageListingContext.Provider
         value={{
            ...viewList,
            listingElRef,
            filterMobileOpen,
            updateFilters,
            clearFilters,
            currentPage,
            setPage,
            updateFiltersDebounce,
            applyFiltersDebounce,
            openFilters,
            closeFilters,
            pageCountStart,
            pageCountEnd,
            showCardsSkeleton,
            showCards,
            data,
         }}
      >
         {children}
      </PageListingContext.Provider>
   );
};

export const PageListing: IPageListing = {
   Container: PageListingContainer,
   ScrollContainer: function ScrollContainer(props) {
      const { listingElRef } = useContext(PageListingContext);
      return <div ref={listingElRef}>{props.children}</div>;
   },
   Context: function ScrollContainer(props: any) {
      const context = useContext(PageListingContext);
      return props.render(context);
   },
   FiltersContainer,
   CardsContainer: CardListingContainer,
   TextResultCount: function ScrollContainer() {
      const context = useContext(PageListingContext);

      return (
         <>
            {context.pageCountStart}-{context.pageCountEnd} de {context.resourcesTotal}
         </>
      );
   },
};
