import type React from "react";
import { useEffect, useRef, useState, useCallback } from "react";
import { createPortal } from "react-dom";

interface DropdownProps {
  isOpen: boolean;
  onClose: () => void;
  children: React.ReactNode;
  className?: string;
  /** Reference element for positioning (button that triggers dropdown) */
  anchorRef?: React.RefObject<HTMLElement>;
  /** Placement: 'left' | 'right' | 'bottom-left' | 'bottom-right' */
  placement?: 'left' | 'right' | 'bottom-left' | 'bottom-right';
}

export const Dropdown: React.FC<DropdownProps> = ({
  isOpen,
  onClose,
  children,
  className = "",
  anchorRef,
  placement = 'right',
}) => {
  const dropdownRef = useRef<HTMLDivElement>(null);
  const [position, setPosition] = useState({ top: 0, left: 0 });

  // Calculate position based on anchor element
  const updatePosition = useCallback(() => {
    if (!isOpen || !anchorRef?.current || !dropdownRef.current) return;
    
    const anchorRect = anchorRef.current.getBoundingClientRect();
    const dropdownRect = dropdownRef.current.getBoundingClientRect();
    
    // For fixed positioning, coordinates are relative to viewport (no scroll offset needed)
    let top = anchorRect.bottom + 8; // 8px = mt-2 equivalent
    let left = anchorRect.left;

    // Handle placement - get width from actual render or fallback to className parsing
    let dropdownWidth = dropdownRect.width;
    if (!dropdownWidth || dropdownWidth === 0) {
      // Try to extract width from className (e.g., "w-64" = 256px, "w-48" = 192px)
      const widthMatch = className.match(/w-(\d+)/);
      if (widthMatch) {
        const widthValue = parseInt(widthMatch[1], 10);
        dropdownWidth = widthValue * 4; // Tailwind: w-64 = 16rem = 256px, so w-N = N*4px
      } else {
        dropdownWidth = 192; // Default fallback
      }
    }
    
    if (placement === 'right') {
      // Align dropdown right edge to button right edge
      left = anchorRect.right - dropdownWidth;
    } else if (placement === 'bottom-right') {
      // Position below and align to right edge of button
      left = anchorRect.right - dropdownWidth;
    } else if (placement === 'bottom-left') {
      // Position below and align to left edge of button
      left = anchorRect.left;
    } else {
      // 'left' - align dropdown left edge to button left edge
      left = anchorRect.left;
    }

    // Edge detection - flip if would overflow viewport
    const viewportWidth = window.innerWidth;
    const viewportHeight = window.innerHeight;
    const dropdownHeight = dropdownRect.height || 200;

    // Check right edge
    if (left + dropdownWidth > viewportWidth) {
      left = anchorRect.left - dropdownWidth;
    }

    // Check bottom edge
    if (anchorRect.bottom + dropdownHeight > viewportHeight) {
      // Position above instead
      top = anchorRect.top - dropdownHeight - 8;
    }

    // Ensure doesn't go off left edge
    if (left < 0) {
      left = 8;
    }

    setPosition({ top, left });
  }, [isOpen, anchorRef, placement]);

  useEffect(() => {
    if (isOpen && anchorRef?.current) {
      // Update on scroll/resize
      const handleUpdate = () => updatePosition();
      window.addEventListener('scroll', handleUpdate, true);
      window.addEventListener('resize', handleUpdate);
      
      // Use multiple requestAnimationFrame calls to ensure dropdown is rendered and measured
      let rafId2: number | undefined;
      const rafId1 = requestAnimationFrame(() => {
        updatePosition();
        // Second frame to ensure dimensions are calculated
        rafId2 = requestAnimationFrame(() => {
          updatePosition();
        });
      });
      
      return () => {
        window.removeEventListener('scroll', handleUpdate, true);
        window.removeEventListener('resize', handleUpdate);
        cancelAnimationFrame(rafId1);
        if (rafId2 !== undefined) cancelAnimationFrame(rafId2);
      };
    }
  }, [isOpen, anchorRef, placement, updatePosition]);

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        dropdownRef.current &&
        !dropdownRef.current.contains(event.target as Node) &&
        !(event.target as HTMLElement).closest(".dropdown-toggle")
      ) {
        onClose();
      }
    };

    if (isOpen) {
      document.addEventListener("mousedown", handleClickOutside);
    }

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [isOpen, onClose]);

  if (!isOpen) return null;

  const dropdownContent = (
    <div
      ref={dropdownRef}
      className={`fixed z-[999999] rounded-xl border border-gray-200 bg-white shadow-theme-lg dark:border-gray-800 dark:bg-gray-dark ${className}`}
      style={{
        top: `${position.top}px`,
        left: `${position.left}px`,
      }}
    >
      {children}
    </div>
  );

  // Portal to body to escape overflow constraints
  return createPortal(dropdownContent, document.body);
};
