"use client";

import * as React from "react";
import { useVirtualizer } from "@tanstack/react-virtual";
import { CheckIcon, ChevronDownIcon } from "lucide-react";
import { getApiEntityId, type Role as ApiRole } from "@/api/permissions/types";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { cn } from "@/lib/utils";

/** Below this count, a plain scroll list avoids popover + virtualizer measure race (empty dropdown). */
const VIRTUALIZE_THRESHOLD = 48;

const TRIGGER_BASE =
  "flex w-full items-center justify-between gap-2 rounded-[14px] border border-white bg-white/60 backdrop-blur-[15px] px-[10px] py-2 text-sm text-[#0a0a0a] shadow-[0px_2px_15px_0px_rgba(0,0,0,0.1)] transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground";

const LIST_SCROLL_CLASS =
  "box-border h-[min(280px,55vh)] min-h-[160px] w-full overflow-y-auto overflow-x-hidden p-1 scrollbar-themed";

type Row = { id: string; label: string };

function buildRows(roles: ApiRole[]): Row[] {
  const out: Row[] = [];
  for (const role of roles) {
    const id = getApiEntityId(role);
    if (!id) continue;
    out.push({
      id,
      label: role.name,
    });
  }
  return out;
}

function roleOptionRow(
  row: Row,
  value: string,
  listId: string,
  onPick: (id: string) => void,
) {
  const isSelected = row.id === value;
  return (
    <button
      key={row.id}
      id={`${listId}-option-${row.id}`}
      type="button"
      role="option"
      aria-selected={isSelected}
      className={cn(
        "relative flex w-full cursor-default items-center gap-2 rounded-sm py-2 pr-8 pl-2 text-left text-sm outline-none select-none hover:bg-accent/80 focus:bg-accent focus:text-accent-foreground",
        isSelected && "bg-accent/30",
      )}
      onClick={() => onPick(row.id)}
    >
      <span className="pointer-events-none absolute right-2 flex size-3.5 items-center justify-center">
        {isSelected ? <CheckIcon className="size-4" /> : null}
      </span>
      <span className="min-w-0 truncate">{row.label}</span>
    </button>
  );
}

type VirtualListProps = {
  listId: string;
  rows: Row[];
  value: string;
  onPick: (id: string) => void;
};

/** Mounted only while popover is open so `getScrollElement` is never stuck on a detached node. */
function VirtualizedRoleListBody({ listId, rows, value, onPick }: VirtualListProps) {
  const parentRef = React.useRef<HTMLDivElement>(null);

  // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Virtual; list unmounts with popover
  const virtualizer = useVirtualizer({
    count: rows.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 36,
    overscan: 10,
    getItemKey: (index) => rows[index]?.id ?? index,
  });

  React.useLayoutEffect(() => {
    virtualizer.measure();
    const id = requestAnimationFrame(() => virtualizer.measure());
    return () => cancelAnimationFrame(id);
  }, [rows.length, virtualizer]);

  return (
    <div
      id={listId}
      ref={parentRef}
      role="listbox"
      className={LIST_SCROLL_CLASS}
    >
      <div
        className="relative w-full"
        style={{ height: `${virtualizer.getTotalSize()}px` }}
      >
        {virtualizer.getVirtualItems().map((vi) => {
          const row = rows[vi.index];
          if (!row) return null;
          const isSelected = row.id === value;
          return (
            <button
              key={row.id}
              id={`${listId}-option-${row.id}`}
              type="button"
              role="option"
              aria-selected={isSelected}
              className={cn(
                "absolute left-0 flex w-full cursor-default items-center gap-2 rounded-sm py-2 pr-8 pl-2 text-left text-sm outline-none select-none hover:bg-accent/80 focus:bg-accent focus:text-accent-foreground",
                isSelected && "bg-accent/30",
              )}
              style={{
                height: `${vi.size}px`,
                transform: `translateY(${vi.start}px)`,
              }}
              onClick={() => onPick(row.id)}
            >
              <span className="pointer-events-none absolute right-2 flex size-3.5 items-center justify-center">
                {isSelected ? <CheckIcon className="size-4" /> : null}
              </span>
              <span className="min-w-0 truncate">{row.label}</span>
            </button>
          );
        })}
      </div>
    </div>
  );
}

export type VirtualizedRoleSelectProps = {
  roles: ApiRole[];
  value: string;
  onValueChange: (id: string) => void;
  disabled?: boolean;
  /** Match `SelectTrigger` `size="sm"` (h-8). */
  size?: "sm" | "default";
  className?: string;
};

export function VirtualizedRoleSelect({
  roles,
  value,
  onValueChange,
  disabled,
  size = "sm",
  className,
}: VirtualizedRoleSelectProps) {
  const [open, setOpen] = React.useState(false);
  const listId = React.useId();

  const rows = React.useMemo(() => buildRows(roles), [roles]);

  const selectedLabel = React.useMemo(() => {
    const fromRows = rows.find((r) => r.id === value)?.label;
    if (fromRows) return fromRows;
    if (!value) return undefined;
    const role = roles.find((r) => getApiEntityId(r) === value);
    if (!role) return undefined;
    return role.name;
  }, [rows, roles, value]);

  const useVirtual = rows.length > VIRTUALIZE_THRESHOLD;

  const handlePick = React.useCallback(
    (id: string) => {
      onValueChange(id);
      setOpen(false);
    },
    [onValueChange],
  );

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <button
          type="button"
          disabled={disabled}
          role="combobox"
          aria-expanded={open}
          aria-controls={listId}
          aria-haspopup="listbox"
          data-slot="virtualized-role-select-trigger"
          data-size={size}
          className={cn(
            TRIGGER_BASE,
            "min-w-0 gap-2",
            size === "sm" ? "h-8 min-h-8 py-0 text-[13px]" : "h-9 min-h-9",
            className,
          )}
        >
          <span
            data-slot="select-value"
            className={cn(
              "block min-w-0 flex-1 truncate text-left font-medium",
              !selectedLabel && "text-muted-foreground",
            )}
            title={selectedLabel ?? undefined}
          >
            {selectedLabel ?? "Choose a role"}
          </span>
          <ChevronDownIcon className="size-4 shrink-0 opacity-50" aria-hidden />
        </button>
      </PopoverTrigger>
      <PopoverContent
        align="start"
        sideOffset={4}
        className="z-50 w-[var(--radix-popover-trigger-width)] min-w-[12rem] max-w-[min(100vw-2rem,28rem)] rounded-[14px] border border-white bg-white/95 p-0 shadow-[0px_2px_15px_0px_rgba(0,0,0,0.1)] backdrop-blur-[15px]"
        onOpenAutoFocus={(e) => e.preventDefault()}
      >
        {rows.length === 0 ? (
          <div className="px-2 py-3 text-center text-sm text-muted-foreground">No roles</div>
        ) : open && useVirtual ? (
          <VirtualizedRoleListBody
            listId={listId}
            rows={rows}
            value={value}
            onPick={handlePick}
          />
        ) : open ? (
          <div id={listId} role="listbox" className={LIST_SCROLL_CLASS}>
            {rows.map((row) => roleOptionRow(row, value, listId, handlePick))}
          </div>
        ) : null}
      </PopoverContent>
    </Popover>
  );
}
