"use client";

import React, { useEffect, useMemo, useState } from "react";
import useBodyScrollLock from "../../hooks/use-body-scroll-lock";
import { cx } from "../../utils";
import { Button } from "../button";
import { MaterialIcon } from "../material-icon";
import { Animation, ModalProps, Shape, Size } from "./types";
import ReactModal from "react-modal";
import { Transition } from "react-transition-group";

const Modal: React.FC<ModalProps> = ({
  size = "md",
  shape = "default",
  animation = "popper",
  centered,
  title,
  isOpen,
  children,
  bodyStyle,
  className,
  bodyClassName,
  portalClassName,
  overlayClassName,
  closeButtonClassName,
  closeWrapperClassName,
  onRequestClose,
  parentSelector,
  hideScrollOnIsOpenFalse = true,
  hideCloseButton = false,
  ...modalProps
}: ModalProps) => {
  // Use the custom hook to lock/unlock the body scroll when the modal is open/closed.
  useBodyScrollLock(isOpen, hideScrollOnIsOpenFalse);

  // Animation cannot run at the same time as the modal opening
  const [isTransitioning, setIsTransitioning] = useState(false);

  useEffect(() => {
    // Run animation one frame after rendering the modal
    setIsTransitioning(isOpen);
  }, [isOpen]);

  const parent = useMemo(() => {
    /* istanbul ignore next */ if (typeof document === "undefined") return null;
    let parent = document.querySelector("main") || document.body;
    if (parentSelector)
      parent = document.querySelector(parentSelector) || document.body;

    return parent;
  }, [parentSelector]);

  if (!parent) return null;

  // Don't render anything when modal is closed
  if (!isOpen) {
    return null;
  }

  const getSizeClasses = (size: Size) => {
    const sizeMap = {
      xl: "inset-[5%] min-h-fit",
      lg: "inset-[10%] min-h-fit",
      md: "inset-[15%] min-h-fit",
      sm: "top-[18%] w-[640px]",
      xs: "w-[calc(100%-30px)]",
    };
    return sizeMap[size];
  };

  const getAnimationClasses = (animation: Animation, state: string) => {
    if (animation === "popper") {
      const baseClasses = "transition-transform duration-300";
      if (state === "entering" || state === "entered") {
        return `${baseClasses} opacity-100 ${state === "entered" ? "translate-y-0 pointer-events-auto" : ""}`;
      }
      if (state === "exiting" || state === "exited") {
        return `${baseClasses} opacity-0 translate-y-[-18px] duration-[180ms]`;
      }
      return `${baseClasses} opacity-0 translate-y-[-18px]`;
    }
    if (animation === "bottomSheet") {
      const baseClasses = "transition-transform duration-200 ease-in-out";
      if (state === "entering" || state === "entered") {
        return `${baseClasses} opacity-100 ${state === "entered" ? "translate-y-0 pointer-events-auto" : ""}`;
      }
      if (state === "exiting" || state === "exited") {
        return `${baseClasses} opacity-0 translate-y-full duration-[180ms]`;
      }
      return `${baseClasses} opacity-0 translate-y-full`;
    }
    return "";
  };

  return (
    <Transition enter exit in={isTransitioning} timeout={0}>
      {(state: string) => (
        <ReactModal
          ariaHideApp={false}
          isOpen={isOpen}
          onRequestClose={onRequestClose}
          closeTimeoutMS={0}
          parentSelector={() => parent}
          className={cx(
            "absolute min-w-[150px] max-w-[calc(100vw-30px)] overflow-auto rounded-lg bg-white outline-none",
            getSizeClasses(size),
            shape === "rounded" && "rounded-3xl",
            centered && "top-0 translate-y-[calc(50vh-50%)]",
            getAnimationClasses(animation, state),
            className
          )}
          portalClassName={cx("z-80", portalClassName)}
          overlayClassName={cx(
            "z-80 fixed inset-0 bg-black/50 flex items-center justify-center pb-[300px]",
            overlayClassName
          )}
          {...modalProps}
        >
          {!hideCloseButton && (
            <div className={cx(closeWrapperClassName)}>
              <Button
                className={cx(
                  "absolute right-0 top-0 float-right h-6 cursor-pointer p-5 text-text",
                  closeButtonClassName
                )}
                onClick={onRequestClose as () => void}
                data-testid="close-button"
                data-track-element-name="modal_close_button"
                data-track-click-text="Close Modal"
                data-track-element-clicked="modal"
              >
                <MaterialIcon name="close" size={24} />
              </Button>
            </div>
          )}

          {title ? (
            <div
              className={cx(
                "border-b border-border-secondary-on-bg-fill px-[7px] py-[7px] text-text"
              )}
            >
              {title}
            </div>
          ) : null}
          <div
            className={cx("p-5", bodyClassName)}
            style={bodyStyle}
            data-testid={modalProps["data-testid"]}
            data-cy={modalProps["data-cy"]}
          >
            {children}
          </div>
        </ReactModal>
      )}
    </Transition>
  );
};

export { Modal };

Modal.displayName = "Modal";

export type { ModalProps, Size, Shape, Animation };
