import { useState, useRef, useEffect, createContext, useContext } from "react";
import { Cog6ToothIcon } from "@heroicons/react/24/outline";
import { motion, AnimatePresence } from "framer-motion";
import { Grid } from "../Grid/Grid";
import { createPortal } from "react-dom";

export const PopOverContext = createContext<boolean>(false);
export const usePopOverContext = () => useContext(PopOverContext);

export const Popover = ({
  children,
  className,
}: {
  children: React.ReactNode | any;
  className?: string;
}) => {
  const [isOpen, setIsOpen] = useState(false);
  const [isMobile, setIsMobile] = useState(false);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const popoverRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const checkMobile = () => setIsMobile(window.innerWidth < 640);
    checkMobile();
    window.addEventListener("resize", checkMobile);
    return () => window.removeEventListener("resize", checkMobile);
  }, []);

  const buttonRect = buttonRef?.current?.getBoundingClientRect();

  useEffect(() => {
    const handleClickOutside = (e: MouseEvent | TouchEvent) => {
      if (
        !buttonRef.current?.contains(e.target as Node) &&
        !popoverRef.current?.contains(e.target as Node)
      ) {
        setIsOpen(false);
      }
    };

    if (isOpen) {
      document.addEventListener("mousedown", handleClickOutside);
      if (isMobile) document.body.style.overflow = "hidden";
    }

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
      if (isMobile) document.body.style.overflow = "";
    };
  }, [isOpen, isMobile]);

  const togglePopover = () => setIsOpen(!isOpen);

  const [position, setPosition] = useState({ top: 0, left: 0 });
  useEffect(() => {
    if (!isOpen || isMobile) return;

    const updatePosition = () => {
      const buttonRect = buttonRef.current?.getBoundingClientRect();
      const popoverElement = popoverRef.current;

      if (!buttonRect) return;

      const viewportHeight = window.innerHeight;
      const viewportWidth = window.innerWidth;
      const scrollY = window.scrollY;
      const scrollX = window.scrollX;

      const padding = 16;
      const maxPopoverHeight = viewportHeight - padding * 2;

      let top = buttonRect.top + scrollY;
      let left = buttonRect.right + scrollX + 8;

      if (popoverElement) {
        const popoverRect = popoverElement.getBoundingClientRect();

        const popoverHeight = Math.min(popoverRect.height, maxPopoverHeight);
        const popoverWidth = popoverRect.width;

        const popoverBottomInViewport = buttonRect.top + popoverHeight;

        if (popoverBottomInViewport > viewportHeight - padding) {
          const overflow = popoverBottomInViewport - (viewportHeight - padding);

          top = buttonRect.top + scrollY - overflow;

          if (top < scrollY + padding) {
            top = scrollY + padding;
          }
        }

        const popoverRightInViewport = buttonRect.right + popoverWidth + 8;
        if (popoverRightInViewport > viewportWidth - padding) {
          left = buttonRect.left + scrollX - popoverWidth - 8;

          if (left < scrollX + padding) {
            left = scrollX + padding;
          }
        }
      } else {
        const estimatedHeight = Math.min(
          (Array.isArray(children) ? children.length : 1) * 50 + 100,
          maxPopoverHeight
        );

        if (buttonRect.top + estimatedHeight > viewportHeight - padding) {
          const overflow =
            buttonRect.top + estimatedHeight - (viewportHeight - padding);

          top = buttonRect.top + scrollY - overflow;
          if (top < scrollY + padding) {
            top = scrollY + padding;
          }
        }

        const estimatedWidth = 300;
        if (buttonRect.right + estimatedWidth + 8 > viewportWidth - padding) {
          left = buttonRect.left + scrollX - estimatedWidth - 8;
          if (left < scrollX + padding) {
            left = scrollX + padding;
          }
        }
      }

      setPosition({ top, left });
    };

    updatePosition();

    const timeoutId = setTimeout(updatePosition, 0);

    window.addEventListener("scroll", updatePosition, true);
    window.addEventListener("resize", updatePosition);

    return () => {
      clearTimeout(timeoutId);
      window.removeEventListener("scroll", updatePosition, true);
      window.removeEventListener("resize", updatePosition);
    };
  }, [isOpen, isMobile, children]);

  return (
    <PopOverContext.Provider value={true}>
      <div className={`relative ${className}`}>
        <motion.button
          ref={buttonRef}
          onClick={togglePopover}
          className={`p-2 rounded-full hover:bg-gray-100/50 dark:hover:bg-gray-800 transition-colors`}
          whileHover={{ scale: 1.05 }}
          whileTap={{ scale: 0.95 }}
        >
          <motion.div animate={{ rotate: isOpen ? 90 : 0 }}>
            <Cog6ToothIcon
              className={`h-5 w-5 ${
                isOpen ? "text-primary-600" : "text-gray-600 dark:text-gray-300"
              }`}
            />
          </motion.div>
        </motion.button>

        {isOpen &&
          createPortal(
            <AnimatePresence>
              <>
                {isMobile && (
                  <motion.div
                    initial={{ opacity: 0 }}
                    animate={{ opacity: 0.4 }}
                    exit={{ opacity: 0 }}
                    className="fixed inset-0 z-9998 bg-black/40 backdrop-blur-sm"
                    onClick={() => setIsOpen(false)}
                  />
                )}

                <motion.div
                  ref={popoverRef}
                  id="popover-content"
                  initial={isMobile ? { y: "100%" } : { opacity: 0, y: -10 }}
                  animate={isMobile ? { y: 0 } : { opacity: 1, y: 0 }}
                  exit={isMobile ? { y: "100%" } : { opacity: 0, y: -10 }}
                  transition={{ type: "spring", damping: 20, stiffness: 300 }}
                  className={`z-9999 bg-white dark:bg-dark-700 rounded-lg shadow-lg ring-1 ring-black/10 dark:ring-white/10 ${
                    isMobile
                      ? "fixed bottom-0 inset-x-0 rounded-t-3xl pb-[env(safe-area-inset-bottom)]"
                      : "fixed max-h-[calc(100vh-32px)]"
                  }`}
                  style={
                    !isMobile
                      ? {
                          top: `${
                            buttonRect?.bottom && buttonRect?.bottom > 700
                              ? position.top - 100
                              : position.top
                          }px`,
                          left: `${position.left}px`,
                        }
                      : {}
                  }
                >
                  {isMobile && (
                    <div className="flex justify-center py-2">
                      <div className="w-10 h-1 bg-gray-300 dark:bg-gray-600 rounded-full" />
                    </div>
                  )}

                  <PopOverContext.Provider value={true}>
                    <Grid
                      container
                      column
                      className="gap-2 p-2 max-h-[calc(100vh-32px)] overflow-y-auto"
                      onClick={() => setIsOpen(false)}
                    >
                      {children}
                    </Grid>
                  </PopOverContext.Provider>
                </motion.div>
              </>
            </AnimatePresence>,
            document.body
          )}
      </div>
    </PopOverContext.Provider>
  );
};
