import { keyCodes } from './keyCodes'

const focusableElements = [
  'input:not([disabled]):not([type=hidden])',
  'textarea:not([disabled])',
  'button:not([disabled])',
  'select',
  'a[href]',
  'iframe',
  '[tabindex]:not([tabindex="-1"])'
];

const TAB_ELEMENT = focusableElements.join(':not([tabindex="-1"]),');

const findElement= (elements)=>{
  let ele=[]
  Object.keys(elements).forEach((element)=>{
    let  elem = elements[element];
    if(elem.getAttribute('data-aria-autofocus') === 'true'){
      ele.push(elem)
    }
  })
  return ele.length?ele[0]:null
}

const getFocusEle = (contentRef)=>{
  let focusEle = contentRef && contentRef.querySelectorAll(TAB_ELEMENT)
  let findFocus = focusEle && findElement(focusEle);
  let firstEle = focusEle && focusEle[0];
  let lastEle = focusEle && focusEle[focusEle.length - 1];
  return { firstEle,lastEle,findFocus }
}

const preventDOMAvailabllityAndFocus=(el)=>{

  requestAnimationFrame(() => {
     el && el.focus();
  });

}

export const restoreFocusTypes = {
  stack : "stack",
  list : "list"
}

const restoreFocusHandler={
      restoreNodes : null,
      set:(restoreFocusId,isNested,updateOnSetRestoreFocus,ownRestoreRef)=>{
        
        restoreFocusHandler.restoreNodes = restoreFocusHandler.restoreNodes || [];
        let newRestoreEle = {
          el : ownRestoreRef || document.activeElement,
          id : restoreFocusId
        };

        if(isNested){
          restoreFocusHandler.restoreNodes.push(newRestoreEle);
        }
        else{
          restoreFocusHandler.restoreNodes = [newRestoreEle];
        }

        if(updateOnSetRestoreFocus){

          restoreFocusHandler.restoreNodes = updateOnSetRestoreFocus( restoreFocusHandler.restoreNodes); 

        }
       
      },
      getLastActiveEl:(restoreFocusId)=>{

        return (restoreFocusHandler.restoreNodes || []).some((item)=>{

              if(item.id === restoreFocusId){

                return item.el;

              }

        });

      },
      clear:(restoreFocusId, isNested, updateOnClearRestoreFocus )=>{

        restoreFocusHandler.fireFocus(restoreFocusId);

        if( restoreFocusHandler.restoreNodes && isNested) {

          restoreFocusHandler.restoreNodes = restoreFocusHandler.restoreNodes.filter((item)=>{

            return item.id === restoreFocusId;
  
          });
  
          if(restoreFocusHandler.restoreNodes.length === 0){
            restoreFocusHandler.restoreNodes = null;
          }

        }
        else{

          restoreFocusHandler.restoreNodes = null;

        }

        if(updateOnClearRestoreFocus){
          restoreFocusHandler.restoreNodes = updateOnClearRestoreFocus(restoreFocusHandler.restoreNodes);
        }
     

      },
      fireFocus:(restoreFocusId)=>{
        let restoreEl = restoreFocusHandler.getLastActiveEl(restoreFocusId);
        preventDOMAvailabllityAndFocus(restoreEl);
      }

}

const restoreFocuser=(isRestoreFocus=false,restoreFocusId='1', isNested=false,updateOnSetRestoreFocus, updateOnClearRestoreFocus, ownRestoreRef=null)=>{

    if(isRestoreFocus){
      restoreFocusHandler.set(restoreFocusId, isNested, updateOnSetRestoreFocus, ownRestoreRef);
    }
    else{
      restoreFocusHandler.clear(restoreFocusId, isNested, updateOnClearRestoreFocus);
    }
}

const autoFocuser = (contentRef,isAutoFocus=false)=>{
 
  if(!contentRef){
    return null;
  }
  
  let { firstEle,lastEle,findFocus } = getFocusEle(contentRef)

  let focusAbleEl = findFocus || firstEle;
  let getActiveClass = focusAbleEl && focusAbleEl.getAttribute('data-active-style')
  if(isAutoFocus){
    preventDOMAvailabllityAndFocus( focusAbleEl );
    focusAbleEl && focusAbleEl.classList.add(getActiveClass);
  }
  else{
    focusAbleEl && focusAbleEl.classList.remove(getActiveClass);
  }

}

const focusLoopHandler = {
  create : function(contentRef){
    if(!focusLoopHandler.firstEle || !focusLoopHandler.lastEle){
      let { firstEle,lastEle } = getFocusEle(contentRef)
      focusLoopHandler.firstEle = firstEle;
      focusLoopHandler.lastEle = lastEle;
    }
    contentRef && contentRef.addEventListener('keydown',focusLoopHandler.keyDownHandler)
  },
  clear : function ( contentRef ){
    focusLoopHandler.firstEle = null;
    focusLoopHandler.lastEle = null;
    contentRef.removeEventListener('keydown',focusLoopHandler.keyDownHandler);
  },
  keyDownHandler : (event)=>{
    if(event.key === 'Tab' || (event.keyCode === 9 && event.shiftKey)){
      if (document.activeElement === focusLoopHandler.firstEle && (event.keyCode === 9 && event.shiftKey)) {

        preventDOMAvailabllity(focusLoopHandler.lastEle);
        event.preventDefault()
      }
      else if(document.activeElement === focusLoopHandler.lastEle && event.key === 'Tab' && !event.shiftKey) {
        preventDOMAvailabllity(focusLoopHandler.firstEle);
        event.preventDefault()
      }
    }
  }
}

const focusLooper=(contentRef, isFocusLoop=false )=>{

  if(!contentRef){
    return null;
  }

  if(isFocusLoop){
    focusLoopHandler.create(contentRef);
  }
  else{
    focusLoopHandler.clear(contentRef);

  }

}




export default {
  autoFocus : autoFocuser,
  focusLoop : focusLooper,
  restoreFocus : restoreFocuser
}

