import { MoreVertical } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";

import type { Person } from "../../types";

interface AllocationBarMenuProps {
  onEdit: () => void;
  onClone?: () => void;
  onSelectAllToRight?: () => void;
  onToggleMultiSelect?: () => void;
  multiSelectActive?: boolean;
  onDelete?: () => void;
  transferPeople?: Person[];
  onTransferPerson?: (personId: number) => void;
}

export function AllocationBarMenuTrigger({
  onEdit,
  onClone,
  onSelectAllToRight,
  onToggleMultiSelect,
  multiSelectActive = false,
  onDelete,
  transferPeople = [],
  onTransferPerson,
}: AllocationBarMenuProps) {
  const triggerRef = useRef<HTMLButtonElement>(null);
  const menuRef = useRef<HTMLDivElement>(null);
  const [open, setOpen] = useState(false);
  const [transferOpen, setTransferOpen] = useState(false);
  const [anchor, setAnchor] = useState<{ top: number; left: number } | null>(null);

  useEffect(() => {
    if (!open) return;
    const onKey = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setOpen(false);
        setTransferOpen(false);
      }
    };
    const onPointerDown = (event: PointerEvent) => {
      const target = event.target as Node;
      if (triggerRef.current?.contains(target)) return;
      if (menuRef.current?.contains(target)) return;
      setOpen(false);
      setTransferOpen(false);
    };
    window.addEventListener("keydown", onKey);
    const timer = window.setTimeout(() => {
      window.addEventListener("pointerdown", onPointerDown);
    }, 0);
    return () => {
      window.clearTimeout(timer);
      window.removeEventListener("keydown", onKey);
      window.removeEventListener("pointerdown", onPointerDown);
    };
  }, [open]);

  const toggleMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
    event.stopPropagation();
    event.preventDefault();
    if (open) {
      setOpen(false);
      setTransferOpen(false);
      return;
    }
    const rect = triggerRef.current?.getBoundingClientRect();
    if (!rect) return;
    setAnchor({ top: rect.bottom + 4, left: rect.right - 200 });
    setOpen(true);
  };

  const close = () => {
    setOpen(false);
    setTransferOpen(false);
  };

  const run = (event: React.MouseEvent, action: () => void) => {
    event.preventDefault();
    event.stopPropagation();
    close();
    window.setTimeout(() => action(), 0);
  };

  return (
    <>
      <button
        aria-expanded={open}
        aria-label="Assignment options"
        className="allocation-bar-menu-btn"
        onClick={toggleMenu}
        onPointerDown={(event) => event.stopPropagation()}
        onPointerUp={(event) => event.stopPropagation()}
        ref={triggerRef}
        type="button"
      >
        <MoreVertical aria-hidden size={16} strokeWidth={2.75} />
      </button>
      {open && anchor
        ? createPortal(
            <div
              className="allocation-bar-menu"
              onMouseDown={(event) => event.stopPropagation()}
              onPointerDown={(event) => event.stopPropagation()}
              ref={menuRef}
              style={{ position: "fixed", top: anchor.top, left: Math.max(8, anchor.left), zIndex: 3500 }}
            >
              <button
                className="allocation-bar-menu-item"
                onClick={(event) => run(event, onEdit)}
                onMouseDown={(event) => event.stopPropagation()}
                type="button"
              >
                Edit
              </button>
              {onTransferPerson && transferPeople.length > 0 ? (
                <>
                  <button
                    className="allocation-bar-menu-item"
                    onClick={(event) => {
                      event.stopPropagation();
                      setTransferOpen((value) => !value);
                    }}
                    onMouseDown={(event) => event.stopPropagation()}
                    type="button"
                  >
                    Transfer
                  </button>
                  {transferOpen ? (
                    <div className="allocation-bar-menu-sub">
                      <select
                        onChange={(event) => {
                          const id = Number(event.target.value);
                          if (id) {
                            close();
                            window.setTimeout(() => onTransferPerson(id), 0);
                          }
                        }}
                        onMouseDown={(event) => event.stopPropagation()}
                        value=""
                      >
                        <option value="">Choose person…</option>
                        {transferPeople.map((person) => (
                          <option key={person.id} value={person.id}>
                            {person.name}
                          </option>
                        ))}
                      </select>
                    </div>
                  ) : null}
                </>
              ) : null}
              {onClone ? (
                <button
                  className="allocation-bar-menu-item"
                  onClick={(event) => run(event, onClone)}
                  onMouseDown={(event) => event.stopPropagation()}
                  type="button"
                >
                  Clone
                </button>
              ) : null}
              {onSelectAllToRight ? (
                <button
                  className="allocation-bar-menu-item"
                  onClick={(event) => run(event, onSelectAllToRight)}
                  onMouseDown={(event) => event.stopPropagation()}
                  type="button"
                >
                  Select All to Right
                </button>
              ) : null}
              {onToggleMultiSelect ? (
                <button
                  className="allocation-bar-menu-item"
                  onClick={(event) => run(event, onToggleMultiSelect)}
                  onMouseDown={(event) => event.stopPropagation()}
                  type="button"
                >
                  {multiSelectActive ? "Disable Multi-Select Mode" : "Enable Multi-Select Mode"}
                </button>
              ) : null}
              {onDelete ? (
                <button
                  className="allocation-bar-menu-item is-danger"
                  onClick={(event) => run(event, onDelete)}
                  onMouseDown={(event) => event.stopPropagation()}
                  type="button"
                >
                  Delete
                </button>
              ) : null}
            </div>,
            document.body,
          )
        : null}
    </>
  );
}
