import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { CheckIcon, ChevronDown, XIcon, WandSparkles } from "lucide-react";

import { cn } from "@/shared/lib/utils";
import { Separator } from "@/shared/common/ui/separator";
import { Button } from "@/shared/common/ui/button";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/shared/common/ui/popover";
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
} from "@/shared/common/ui/command";
import { t } from "i18next";

const normalizeSearchText = (value: string) =>
  value.normalize("NFKC").toLocaleLowerCase().replace(/\s+/g, " ").trim();

/**
 * Variants for the multi-select component to handle different styles.
 * Uses class-variance-authority (cva) to define different styles based on "variant" prop.
 */
const multiSelectVariants = cva(
  "m-1 transition ease-in-out delay-150 hover:-translate-y-1 hover:scale-110 duration-300",
  {
    variants: {
      variant: {
        default:
          "border-foreground/10 text-foreground bg-card hover:bg-card/80",
        secondary:
          "border-foreground/10 bg-secondary text-secondary-foreground hover:bg-secondary/80",
        destructive:
          "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
        inverted: "inverted",
        dropDown:
          "w-full border border-foreground/10 text-foreground bg-card hover:bg-card/80 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 transition duration-200",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  },
);

/**
 * Props for MultiSelect component
 */
interface MultiSelectProps
  extends
    React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof multiSelectVariants> {
  /**
   * An array of option objects to be displayed in the multi-select component.
   * Each option object has a label, value, and an optional icon.
   */
  options: {
    /** The text to display for the option. */
    label: string;
    /** The unique value associated with the option. */
    value: string;
    /** Optional icon component to display alongside the option. */
    icon?: React.ComponentType<{ className?: string }>;
  }[];

  /**
   * Callback function triggered when the selected values change.
   * Receives an array of the new selected values.
   */
  onValueChange: (value: string[]) => void;

  /** The default selected values when the component mounts. */
  defaultValue?: string[];

  /**
   * Placeholder text to be displayed when no values are selected.
   * Optional, defaults to "Select options".
   */
  placeholder?: string;

  /**
   * Animation duration in seconds for the visual effects (e.g., bouncing badges).
   * Optional, defaults to 0 (no animation).
   */
  animation?: number;

  /**
   * Maximum number of items to display. Extra selected items will be summarized.
   * Optional, defaults to 3.
   */
  maxCount?: number;

  /**
   * The modality of the popover. When set to true, interaction with outside elements
   * will be disabled and only popover content will be visible to screen readers.
   * Optional, defaults to false.
   */
  modalPopover?: boolean;

  /**
   * If true, renders the multi-select component as a child of another component.
   * Optional, defaults to false.
   */
  asChild?: boolean;

  /**
   * Additional class names to apply custom styles to the multi-select component.
   * Optional, can be used to add custom styles.
   */
  className?: string;

  /**
   * Current selected values
   */
  value?: string[];
}

export const MultiSelect = React.forwardRef<
  HTMLButtonElement,
  MultiSelectProps
>(
  (
    {
      options = [],
      onValueChange,
      variant,
      defaultValue = [],
      placeholder = "Select options",
      animation = 0,
      maxCount = 3,
      modalPopover = false,
      asChild = false,
      className,
      value,
      ...props
    },
    ref,
  ) => {
    const [selectedValues, setSelectedValues] = React.useState<string[]>(
      value || defaultValue,
    );
    const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
    const [isAnimating, setIsAnimating] = React.useState(false);
    const [isExtraOpen, setIsExtraOpen] = React.useState(false);

    React.useEffect(() => {
      if (value !== undefined) {
        setSelectedValues(value);
      }
    }, [value]);

    const handleInputKeyDown = (
      event: React.KeyboardEvent<HTMLInputElement>,
    ) => {
      if (event.key === "Enter") {
        setIsPopoverOpen(true);
      } else if (event.key === "Backspace" && !event.currentTarget.value) {
        const newSelectedValues = [...selectedValues];
        newSelectedValues.pop();
        setSelectedValues(newSelectedValues);
        onValueChange(newSelectedValues);
      }
    };

    const toggleOption = (option: string) => {
      const newSelectedValues = selectedValues.includes(option)
        ? selectedValues.filter((value) => value !== option)
        : [...selectedValues, option];
      setSelectedValues(newSelectedValues);
      onValueChange(newSelectedValues);
    };

    // Function to remove a specific item without opening the dropdown
    const removeItem = (valueToRemove: string, event: React.MouseEvent) => {
      event.stopPropagation(); // Prevent dropdown from opening
      const newSelectedValues = selectedValues.filter(
        (value) => value !== valueToRemove,
      );
      setSelectedValues(newSelectedValues);
      onValueChange(newSelectedValues);
    };

    const handleClear = (event: React.MouseEvent) => {
      event.stopPropagation(); // Prevent dropdown from opening
      setSelectedValues([]);
      onValueChange([]);
    };

    const toggleAll = () => {
      if (selectedValues.length === options.length) {
        handleClear(new MouseEvent("click") as unknown as React.MouseEvent);
      } else {
        const allValues = options.map((option) => option.value);
        setSelectedValues(allValues);
        onValueChange(allValues);
      }
    };

    return (
      <Popover
        open={isPopoverOpen}
        onOpenChange={setIsPopoverOpen}
        modal={modalPopover}>
        <PopoverTrigger asChild>
          <Button
            ref={ref}
            {...props}
            className={cn(
              "flex w-full p-2 rounded-md border min-h-10 h-auto items-center justify-between bg-background hover:bg-background/90 [&_svg]:pointer-events-auto",
              className,
            )}>
            {selectedValues.length > 0 ? (
              <div className="flex justify-between items-center w-full">
                <div className="flex flex-wrap gap-1 items-center">
{selectedValues.slice(0, maxCount).map((value) => {
                    const option = options.find((o) => o.value === value);
                    const IconComponent = option?.icon;
                    return (
                      <div
                        key={value}
                        className="flex items-center gap-1 px-2 py-1 bg-primary/10 text-primary border border-primary/20 dark:bg-primary/20 dark:text-primary-foreground dark:border-primary/40 rounded-md">
                        {IconComponent && (
                          <IconComponent className="h-3 w-3 mr-1" />
                        )}
                        <span className="max-w-[150px] truncate text-sm">
                          {option?.label}
                        </span>
                        <XIcon
                          className="h-3.5 w-3.5 cursor-pointer text-primary dark:text-primary-foreground hover:text-red-600 ml-1"
                          onClick={(e) => removeItem(value, e)}
                        />
                      </div>
                    );
                  })}
                  {selectedValues.length > maxCount && (
                    <Popover
                      open={isExtraOpen}
                      onOpenChange={setIsExtraOpen}
                      modal={true}>
                      <PopoverTrigger asChild>
                        <div
                          role="button"
                          tabIndex={0}
                          onPointerDown={(e) => e.stopPropagation()}
                          onClick={(e) => {
                            e.stopPropagation();
                            setIsExtraOpen((prev) => !prev);
                          }}
                          onKeyDown={(e) => {
                            if (e.key === "Enter" || e.key === " ") {
                              e.preventDefault();
                              e.stopPropagation();
                              setIsExtraOpen((prev) => !prev);
                            }
                          }}
                          className="flex items-center gap-1 px-2 py-1 bg-gray-100 text-gray-700 border border-gray-200 rounded-md cursor-pointer hover:bg-gray-200 transition-colors dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600 dark:hover:bg-gray-600"
                          title={t("msg.selectAll") /* tooltip fallback */}>
                          <span className="text-sm">{`+ ${
                            selectedValues.length - maxCount
                          } more`}</span>
                        </div>
                      </PopoverTrigger>
                      <PopoverContent
                        align="start"
                        className="w-72 p-0"
                        onPointerDown={(e) => e.stopPropagation()}
                        onClick={(e) => e.stopPropagation()}>
                        <div className="flex items-center justify-between border-b px-3 py-2">
                          <span className="text-xs font-semibold text-slate-700 dark:text-slate-200">
                            {t("ApprovalPage.Selected", "Selected")}
                          </span>
<span className="rounded-full bg-primary/15 px-2 py-0.5 text-xs font-medium text-primary dark:bg-primary/30 dark:text-primary-foreground">
                             {selectedValues.length}
                           </span>
                        </div>
                        <div className="max-h-64 overflow-y-auto py-1">
                          {selectedValues.slice(maxCount).map((val) => {
                            const option = options.find((o) => o.value === val);
                            if (!option) return null;
                            const IconComponent = option.icon;
                            return (
                              <div
                                key={val}
                                className="flex items-center justify-between gap-2 px-3 py-1.5 hover:bg-slate-50 dark:hover:bg-slate-800">
                                <span className="flex items-center gap-2 min-w-0">
                                  {IconComponent && (
                                    <IconComponent className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
                                  )}
<span className="text-sm truncate">
                                     {option.label}
                                   </span>
                                 </span>
                                 <XIcon
                                   className="h-3.5 w-3.5 cursor-pointer text-slate-500 dark:text-slate-400 hover:text-red-600 shrink-0"
                                   onClick={(e) => removeItem(val, e)}
                                 />
                               </div>
                            );
                          })}
                        </div>
                      </PopoverContent>
                    </Popover>
                  )}
                </div>
                <div className="flex items-center justify-between">
                  <ChevronDown className="h-4 mx-2 cursor-pointer text-muted-foreground" />
                </div>
              </div>
            ) : (
              <div className="flex items-center justify-between w-full mx-auto">
                <span className="text-sm text-muted-foreground mx-3">
                  {placeholder}
                </span>
                <ChevronDown className="h-4 cursor-pointer text-muted-foreground mx-2" />
              </div>
            )}
          </Button>
        </PopoverTrigger>
        <PopoverContent
          className="w-auto p-0 max-w-[400px] dark:bg-gray-800 dark:border-gray-700"
          align="start"
          onEscapeKeyDown={() => setIsPopoverOpen(false)}
          onWheel={(e) => {
            // Prevent the wheel event from bubbling up to parent elements
            e.stopPropagation();
          }}>
          <Command
            filter={(value, search, keywords = []) => {
              const normalizedSearch = normalizeSearchText(search);
              if (!normalizedSearch) return 1;

              const haystacks = [value, ...keywords]
                .map((item) => normalizeSearchText(item))
                .filter(Boolean);

              return haystacks.some((item) => item.includes(normalizedSearch))
                ? 1
                : 0;
            }}>
            <CommandInput
              placeholder={t("ApprovalPage.Search")}
              onKeyDown={handleInputKeyDown}
            />
            <CommandList className="max-h-[200px] overflow-y-auto custom-scrollbar scroll-container">
              <CommandEmpty>{t("common.noResult")}</CommandEmpty>
              <CommandGroup>
                <CommandItem
                  key="all"
                  onSelect={toggleAll}
                  className="cursor-pointer">
                  <div
                    className={cn(
                      "mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
                      selectedValues.length === options.length
                        ? "bg-primary text-primary-foreground"
                        : "opacity-50 [&_svg]:invisible",
                    )}>
                    <CheckIcon className="h-4 w-4" />
                  </div>
                  <span>({t("msg.selectAll")})</span>
                </CommandItem>
                {options.map((option) => {
                  const isSelected = selectedValues.includes(option.value);

                  return (
                    <CommandItem
                      key={option.value}
                      value={option.label}
                      keywords={[option.value, option.label]}
                      onSelect={() => toggleOption(option.value)}
                      className="cursor-pointer">
                      <div
                        className={cn(
                          "mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
                          isSelected
                            ? "bg-primary text-primary-foreground"
                            : "opacity-50 [&_svg]:invisible",
                        )}>
                        <CheckIcon className="h-4 w-4" />
                      </div>
                      {option.icon && (
                        <option.icon className="mr-2 h-4 w-4 text-muted-foreground" />
                      )}
                      <span>{option.label}</span>
                    </CommandItem>
                  );
                })}
              </CommandGroup>
              <CommandSeparator />
              <CommandGroup>
                <div className="flex items-center justify-between">
                  {selectedValues.length > 0 && (
                    <>
                      <CommandItem
                        onClick={handleClear}
                        className="flex-1 justify-center cursor-pointer">
                        {t("userIncoming.Clear")}
                      </CommandItem>
                      <Separator
                        orientation="vertical"
                        className="flex min-h-6 h-full"
                      />
                    </>
                  )}
                  <CommandItem
                    onSelect={() => setIsPopoverOpen(false)}
                    className="flex-1 justify-center cursor-pointer max-w-full">
                    {t("complaint.close")}
                  </CommandItem>
                </div>
              </CommandGroup>
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>
    );
  },
);

MultiSelect.displayName = "MultiSelect";
