"use client";

import { lockScroll, unlockScroll } from "@/lib/dom/scroll-lock";
import { AnimatePresence, motion } from "motion/react";
import { useEffect, useLayoutEffect, type ReactNode } from "react";
import { IconClose } from "./icons";

const useIsomorphicLayoutEffect =
  typeof window !== "undefined" ? useLayoutEffect : useEffect;

export type ModalSize = "sm" | "md" | "lg";

const MODAL_SIZE_CLASS: Record<ModalSize, string> = {
  sm: "max-w-[400px]",
  md: "max-w-[480px]",
  lg: "max-w-[720px]",
};

type ModalProps = {
  open: boolean;
  onClose: () => void;
  title: string;
  children: ReactNode;
  footer?: ReactNode;
  ariaLabel?: string;
  size?: ModalSize;
  maxWidthClassName?: string;
};

export function Modal({
  open,
  onClose,
  title,
  children,
  footer,
  ariaLabel,
  size = "md",
  maxWidthClassName,
}: ModalProps) {
  const widthClassName = maxWidthClassName ?? MODAL_SIZE_CLASS[size];
  useIsomorphicLayoutEffect(() => {
    if (!open) return;

    lockScroll();

    return () => {
      unlockScroll();
    };
  }, [open]);

  useEffect(() => {
    if (!open) return;

    function handleKeyDown(event: KeyboardEvent) {
      if (event.key === "Escape") {
        onClose();
      }
    }

    document.addEventListener("keydown", handleKeyDown);

    return () => {
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [open, onClose]);

  return (
    <AnimatePresence>
      {open && (
        <motion.div
          className="fixed inset-0 z-50 flex items-center justify-center bg-neutral-100/40 p-6"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          transition={{ duration: 0.2 }}
          role="dialog"
          aria-modal="true"
          aria-label={ariaLabel ?? title}
          onClick={onClose}
        >
          <motion.div
            className={`flex max-h-[calc(100vh-3rem)] w-full flex-col overflow-hidden rounded-[10px] border border-neutral-40 bg-neutral-10 ${widthClassName}`}
            initial={{ opacity: 0, y: 12, scale: 0.96 }}
            animate={{ opacity: 1, y: 0, scale: 1 }}
            exit={{ opacity: 0, y: 12, scale: 0.96 }}
            transition={{ duration: 0.25, ease: [0.16, 1, 0.3, 1] }}
            onClick={(event) => event.stopPropagation()}
          >
            <div className="flex items-center gap-2 px-5 pt-5">
              <h2 className="text-l-medium flex-1 text-neutral-100">{title}</h2>
              <button
                type="button"
                onClick={onClose}
                className="flex size-5 shrink-0 items-center justify-center text-neutral-100 transition-colors hover:text-neutral-70"
                aria-label="Tutup"
              >
                <IconClose className="size-5" />
              </button>
            </div>

            <div className="flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-5">
              {children}
            </div>

            {footer && (
              <div className="flex items-center gap-2 px-5 pb-5">{footer}</div>
            )}
          </motion.div>
        </motion.div>
      )}
    </AnimatePresence>
  );
}
