import { useState, useEffect, useRef } from 'react';
import { ModalSetter } from '../../../../lib/types/modal.interface';
import ModalService from '../services/ModalService';
import styles from './ModalRoot.module.scss';

export default function ModalRoot() {
  const [modal, setModal] = useState<ModalSetter<Object> | null>(null);
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    ModalService.on('open', ({ component, props, target, resolve }) => {
      setModal({
        component,
        props,
        resolve,
        close: (...args) => {
          setModal(null);
          resolve?.call(null, ...args);
          target?.focus();
        },
      });
    });
  }, []);

  useEffect(() => {
    if (!modal) {
      return;
    }

    function handleEscapeKey(e: KeyboardEvent) {
      if (e.key === 'Escape') {
        modal?.close?.call(null, false);
      }
    }

    // Off click listener
    function handleClickOutside(event: MouseEvent | TouchEvent) {
      if (
        ref.current &&
        !(ref.current as unknown as HTMLElement).contains(
          event.target as HTMLElement
        )
      ) {
        modal?.close?.call(null, false);
      }
    }

    window.addEventListener('keyup', handleEscapeKey);
    document.body.style.overflow = 'hidden';
    document.addEventListener('mousedown', handleClickOutside);
    document.addEventListener('touchstart', handleClickOutside);

    return () => {
      window.removeEventListener('keyup', handleEscapeKey);
      document.body.style.overflow = '';
      document.removeEventListener('mousedown', handleClickOutside);
      document.removeEventListener('touchstart', handleClickOutside);
    };
  }, [modal]);

  const ModalComponent = modal?.component ? modal.component : null;

  return (
    <section className={modal?.component ? styles.modalRoot : ''}>
      {ModalComponent && (
        <ModalComponent {...modal?.props} modalRef={ref} close={modal!.close} />
      )}
    </section>
  );
}
