import cn from "classnames";
import React, { forwardRef, useEffect, useRef } from "react";
import PropTypes from "prop-types";
import { IModalProps } from "./modal.d";

const FOCUSABLE_ELEMENTS = [
  'a[href]:not([tabindex^="-"]):not([inert])',
  'area[href]:not([tabindex^="-"]):not([inert])',
  "input:not([disabled]):not([inert])",
  "select:not([disabled]):not([inert])",
  "textarea:not([disabled]):not([inert])",
  "button:not([disabled]):not([inert])",
  'iframe:not([tabindex^="-"]):not([inert])',
  'audio:not([tabindex^="-"]):not([inert])',
  'video:not([tabindex^="-"]):not([inert])',
  '[contenteditable]:not([tabindex^="-"]):not([inert])',
  '[tabindex]:not([tabindex^="-"]):not([inert])'
];

const Modal: React.FC<IModalProps> = forwardRef((props, ref: React.Ref<HTMLDivElement>) => {
  const {
    children,
    className,
    isCentered,
    isCloseOnEscapeKey,
    isFocusOnFirstFocusableEl,
    isRelative,
    isScrollable,
    onClose,
    size,
    isRightPanel,
    rightPanelWidth,
    backdrop
  } = props;
  const dataTestId = props["data-testid"] || "honey-ui-modal";
  const refRoot = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    const onKeyPressed = (event: KeyboardEvent) =>
      isCloseOnEscapeKey && event.key === "Escape" && onClose();

    if (isFocusOnFirstFocusableEl && refRoot && refRoot.current) {
      const modalBody = refRoot.current.querySelector(".modal-body");
      const modalFooter = refRoot.current.querySelector(".modal-footer");
      const modalHeader = refRoot.current.querySelector(".modal-footer");
      const el =
        (modalBody &&
          (modalBody.querySelectorAll(FOCUSABLE_ELEMENTS.join(","))[0] as HTMLElement)) ||
        (modalFooter &&
          (modalFooter.querySelectorAll(FOCUSABLE_ELEMENTS.join(","))[0] as HTMLElement)) ||
        (modalHeader &&
          (modalHeader.querySelectorAll(FOCUSABLE_ELEMENTS.join(","))[0] as HTMLElement));

      if (el) {
        el.focus();
      }
    }

    if (!isRelative) {
      document.body.classList.add("modal-open");
    }

    document.addEventListener("keyup", onKeyPressed, false);

    return () => {
      if (!isRelative) {
        document.body.classList.remove("modal-open");
      }
      document.removeEventListener("keyup", onKeyPressed, false);
    };
  }, []);

  return (
    <>
      <div
        ref={ref}
        role="dialog"
        tabIndex={-1}
        className={cn("modal d-block fade show", { "position-relative": isRelative }, className)}
        data-testid={dataTestId}
      >
        <div
          role="presentation"
          className="position-absolute w-100 h-100"
          onClick={backdrop ? onClose : undefined}
          data-testid={`${dataTestId}-overlay`}
        />
        <div
          data-testid={`${dataTestId}-dialog`}
          role="document"
          className={cn("modal-dialog", {
            "modal-dialog-scrollable": isScrollable,
            "modal-dialog-centered": isCentered,
            "modal-xl": size === "xl",
            "modal-lg": size === "lg",
            "modal-sm": size === "sm",
            "position-absolute m-0": isRightPanel
          })}
          style={
            isRightPanel
              ? { top: "0", right: "0", minHeight: "100%", width: rightPanelWidth || "600px" }
              : undefined
          }
        >
          <div
            ref={refRoot}
            className="modal-content"
            style={isRightPanel ? { maxHeight: "100%", borderRadius: "0" } : undefined}
          >
            {children}
          </div>
        </div>
      </div>
      <div
        data-testid={`${dataTestId}-backdrop`}
        className={cn("modal-backdrop fade show", { "position-absolute h-100 w-100": isRelative })}
      />
    </>
  );
});

Modal.displayName = "Modal";

Modal.propTypes = {
  backdrop: PropTypes.bool,
  className: PropTypes.string,
  isCentered: PropTypes.bool,
  isCloseOnEscapeKey: PropTypes.bool,
  isFocusOnFirstFocusableEl: PropTypes.bool,
  isRelative: PropTypes.bool,
  isScrollable: PropTypes.bool,
  onClose: PropTypes.func.isRequired,
  size: PropTypes.oneOf(["xl", "lg", "sm", "initial"])
};

Modal.defaultProps = {
  backdrop: true,
  isCloseOnEscapeKey: true,
  isFocusOnFirstFocusableEl: true
};

export default Modal;
