"use client";

import {
  useCallback,
  useEffect,
  useRef,
  useState,
} from "react";
import { createPortal } from "react-dom";
import type { ColumnDef } from "@tanstack/react-table";
import { BsThreeDotsVertical } from "react-icons/bs";

import type { Package } from "../types/package";

interface PackageColumnsProps {
  onEdit: (item: Package) => void;
  onDelete: (item: Package) => void;
}

type MenuPosition = {
  top: number;
  left: number;
  origin: "top" | "bottom";
};

const MENU_WIDTH = 144;
const MENU_HEIGHT = 96;
const GAP = 8;
const SCREEN_PADDING = 12;

function ActionCell({
  item,
  onEdit,
  onDelete,
}: {
  item: Package;
  onEdit: (item: Package) => void;
  onDelete: (item: Package) => void;
}) {
  const [open, setOpen] = useState(false);
  const [position, setPosition] = useState<MenuPosition>({
    top: 0,
    left: 0,
    origin: "top",
  });

  const buttonRef = useRef<HTMLButtonElement>(null);
  const menuRef = useRef<HTMLDivElement>(null);

  const updatePosition = useCallback(() => {
    const button = buttonRef.current;
    if (!button) return;

    const rect = button.getBoundingClientRect();

    const spaceBottom = window.innerHeight - rect.bottom;
    const spaceTop = rect.top;

    const openUp = spaceBottom < MENU_HEIGHT + GAP && spaceTop > spaceBottom;

    const top = openUp
      ? Math.max(SCREEN_PADDING, rect.top - MENU_HEIGHT - GAP)
      : Math.min(
          rect.bottom + GAP,
          window.innerHeight - MENU_HEIGHT - SCREEN_PADDING,
        );

    let left = rect.right - MENU_WIDTH;

    left = Math.max(SCREEN_PADDING, left);
    left = Math.min(left, window.innerWidth - MENU_WIDTH - SCREEN_PADDING);

    setPosition({
      top,
      left,
      origin: openUp ? "bottom" : "top",
    });
  }, []);

  const closeMenu = () => setOpen(false);

  const handleOpen = () => {
    updatePosition();
    setOpen((prev) => !prev);
  };

  useEffect(() => {
    if (!open) return;

    const handleOutsideClick = (event: MouseEvent) => {
      const target = event.target as Node;

      if (
        buttonRef.current?.contains(target) ||
        menuRef.current?.contains(target)
      ) {
        return;
      }

      closeMenu();
    };

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") closeMenu();
    };

    window.addEventListener("resize", updatePosition);
    window.addEventListener("scroll", updatePosition, true);
    document.addEventListener("mousedown", handleOutsideClick);
    document.addEventListener("keydown", handleKeyDown);

    return () => {
      window.removeEventListener("resize", updatePosition);
      window.removeEventListener("scroll", updatePosition, true);
      document.removeEventListener("mousedown", handleOutsideClick);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [open, updatePosition]);

  return (
    <>
      <button
        ref={buttonRef}
        type="button"
        onClick={handleOpen}
        aria-label="Package actions"
        aria-haspopup="menu"
        aria-expanded={open}
        className="
          inline-flex h-8 w-8 cursor-pointer items-center justify-center
          rounded-full text-link-1 transition
          hover:bg-link-1/10
          focus:outline-none focus:ring-2 focus:ring-link-1/30
        "
      >
        <BsThreeDotsVertical size={22} />
      </button>

      {open &&
        typeof document !== "undefined" &&
        createPortal(
          <div
            ref={menuRef}
            role="menu"
            style={{
              top: position.top,
              left: position.left,
              width: MENU_WIDTH,
              transformOrigin:
                position.origin === "top" ? "top right" : "bottom right",
            }}
            className="
              fixed z-999 overflow-hidden rounded-xl
              border border-[#E7E3F2] bg-white py-2
              shadow-[0_12px_40px_rgba(15,23,42,0.18)]
            "
          >
            <button
              type="button"
              role="menuitem"
              onClick={() => {
                onEdit(item);
                closeMenu();
              }}
              className="
                block w-full cursor-pointer px-4 py-2.5 text-left
                text-sm font-medium text-link-1 transition-colors
                hover:bg-link-1/5
              "
            >
              Edit
            </button>

            <button
              type="button"
              role="menuitem"
              onClick={() => {
                onDelete(item);
                closeMenu();
              }}
              className="
                block w-full cursor-pointer px-4 py-2.5 text-left
                text-sm font-medium text-danger transition-colors
                hover:bg-danger-light
              "
            >
              Delete
            </button>
          </div>,
          document.body,
        )}
    </>
  );
}

export function packageColumns({
  onEdit,
  onDelete,
}: PackageColumnsProps): ColumnDef<Package>[] {
  return [
    { accessorKey: "title", header: "Title" },
    { accessorKey: "description", header: "Description" },
    { accessorKey: "price", header: "Price" },
    { accessorKey: "credits", header: "Credits" },
    {
      accessorKey: "status",
      header: "Status",
      cell: ({ row }) => {
        const status = row.original.status;

        return (
          <span
            className={`inline-flex rounded-full px-3 py-1 text-sm font-medium ${
              status === "Active"
                ? "bg-success-light text-success"
                : "bg-danger-light text-danger"
            }`}
          >
            {status}
          </span>
        );
      },
    },
    {
      id: "action",
      header: "Action",
      cell: ({ row }) => (
        <ActionCell
          item={row.original}
          onEdit={onEdit}
          onDelete={onDelete}
        />
      ),
    },
  ];
}