import { MutableRefObject, useEffect, useRef, useState } from 'react';

/**
 * Para facilitar alguns eventos,
 * foi criado esssa array que possui algumas eventos personalizados
 */
const events = {
   'keydown.arrowdown': {
      event: 'keydown',
      fn: (event, callback) => {
         if (event.keyCode === 40) {
            callback(event);
         }
      },
   },
   'keydown.arrowup': {
      event: 'keydown',
      fn: (event, callback) => {
         if (event.keyCode === 38) {
            callback(event);
         }
      },
   },
   'keydown.enter': {
      event: 'keydown',
      fn: (event, callback) => {
         if (event.keyCode === 13 || event.code === 'Enter' || event.code === 'NumpadEnter') {
            callback(event);
         }
      },
   },
   'keydown.tab': {
      event: 'keydown',
      fn: (event, callback) => {
         if (event.keyCode === 9) {
            callback(event);
         }
      },
   },
};

type IEventsName = string | 'keydown.arrowdown' | 'keydown.arrowup' | 'keydown.enter' | 'keydown.tab';

export function useEventListener(
   eventName: IEventsName,
   handler: (ev: Event) => void,
   element?: MutableRefObject<any>,
): void {
   // Create a ref that stores handler
   const savedHandler: any = useRef();

   // Update ref.current value if handler changes.
   // This allows our effect below to always get latest handler ...
   // ... without us needing to pass it in effect deps array ...
   // ... and potentially cause effect to re-run every render.
   useEffect(() => {
      savedHandler.current = handler;
   }, [handler]);

   useEffect(
      () => {
         // Make sure element supports addEventListener
         const el = element && element.current ? element.current : window;

         const isSupported = el && el.addEventListener;
         if (!isSupported) return;

         // Events Customs
         if (events[eventName]) {
            const eventListener = (event: any): any => events[eventName].fn(event, savedHandler.current);
            el.addEventListener(events[eventName].event, eventListener);

            // Remover event listener
            return (): void => {
               el.removeEventListener(events[eventName].event, eventListener);
            };
         }

         const eventListener = (event: any): any => savedHandler.current(event);
         el.addEventListener(eventName, eventListener);

         // Remover event listener
         return (): void => {
            el.removeEventListener(eventName, eventListener);
         };
      },
      [eventName, element], // Re-run if eventName or element changes
   );
}
