import React, {
  FC,
  ReactNode,
  RefObject,
  useEffect,
  useRef,
  useState
} from 'react'

import ReactDOM from 'react-dom'

import Button from '../button'
import Modal from './modal'

type LaunchModalProps = {
  blurId?: string,
  button?: boolean,
  children: ReactNode,
  launchText?: string,
  modalId: string,
  size?: string,
  title: string,
  variant?: string,
  [other:string]: unknown
}

const addARIAHidden = (elements: Element[], modalId: string): void => {
  for (let i: number = 0; i < elements.length; i++) {
    if (elements[i].id !== modalId) {
      elements[i].setAttribute('aria-hidden', 'true')
    }
  }
}

const removeARIAHidden = (elements: Element[]): void => {
  for (let i: number = 0; i < elements.length; i++) {
    elements[i].removeAttribute('aria-hidden')
  }
}


const getBodyNonScriptChildren = (): Element[] => {
  const bodyChildren: HTMLCollection = document.body.children
  let nonScriptChildren: Element[] = []

  const excludeTags: string[] = ['SCRIPT', 'NOSCRIPT']

  for (let i: number = 0; i < bodyChildren.length; i++) {
    if (!excludeTags.includes(bodyChildren[i].tagName)) {
      nonScriptChildren.push(bodyChildren[i])
    }
  }

  return nonScriptChildren
}

const focusLaunchElement = (ref: RefObject<HTMLDivElement> | null): void => {
  if (!ref || !ref.current) {
    return
  }

  const button: HTMLButtonElement | null = ref.current.querySelector('button')

  if (button) {
    button.focus()
  }
}

const LaunchModal:FC<LaunchModalProps> = ({
  blurId='',
  button,
  children,
  launchText,
  modalId,
  size='sm',
  title,
  variant='outline-indigo',
  ...other
}: LaunchModalProps) => {
  const [showModal, setShowModal] = useState(false)
  const launchRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (showModal) {
      addARIAHidden(getBodyNonScriptChildren(), modalId)
      return
    }

    focusLaunchElement(launchRef)
    
    removeARIAHidden(getBodyNonScriptChildren())
  }, [modalId, launchRef, showModal])

  return (
    <div ref={launchRef}>
      {button
        ?
          <Button
            onClick={() => setShowModal(true)}
            size={size}
            variant={variant}
            tabIndex={0}
            {...other}
          >
            {launchText}
          </Button>
        :
          <button
            onClick={() => setShowModal(true)}
            type="button"
            tabIndex={0}
          >
            <div {...other}>{launchText}</div>
          </button>
      }
      {typeof(window) !== `undefined` &&
        ReactDOM.createPortal(
          <Modal
            blurId={blurId}
            id={modalId}
            showModal={showModal}
            setModalClosed={() => setShowModal(false)}
            setModalOpen={() => setShowModal(true)}
            title={title}
          >
            {children}
          </Modal>,
          document.body
        )
      }
   </div>
  )
}

export default LaunchModal
