"use client";

import React, { useMemo } from "react";
import { cx } from "../../utils";
import { Text } from "../text";
import { FilterOptions, SelectOption, SelectProps } from "./types";
import ReactSelect, { createFilter } from "react-select";

type SelectSize = NonNullable<SelectProps["size"]>;

const SIZE_CLASSES: Record<SelectSize, string> = {
  sm: "h-12 px-3 rounded-lg",
  md: "h-14 px-3 rounded-xl",
  lg: "h-16 px-3 rounded-2xl",
};

export const Select: React.FC<SelectProps> = React.memo(
  ({
    options,
    className,
    controlClassName,
    value,
    isCustomStyle = false,
    placeholder,
    required,
    onChange,
    filterOptions,
    hasError,
    error,
    menuClassName,
    helperText,
    label,
    labelClassName,
    singleValueClassName,
    size = "md",
    variant = "default",
    "data-cy": dataCy,
    "data-testid": dataTestId,
    ...rest
  }) => {
    const memoizedFilterOption = useMemo(
      () => createFilter(filterOptions),
      [filterOptions]
    );

    const memoizedClassNames = useMemo(
      () => ({
        control: ({ isFocused }: any) =>
          cx(
            SIZE_CLASSES[size] ?? SIZE_CLASSES.md,
            "border border-input-border bg-white hover:not-focus:border-input-border-hover",
            {
              "border-input-border-selected outline outline-2 outline-input-border-selected":
                isFocused && !hasError,
              "border-input-border-critical shadow-none": hasError,
            },
            controlClassName
          ),
        indicatorSeparator: () => "hidden",
        dropdownIndicator: ({ selectProps }: any) =>
          isCustomStyle
            ? selectProps.value
              ? "hidden"
              : "block"
            : `block text-icon-default ${hasError ? "text-icon-critical" : ""}`,
        singleValue: () =>
          cx(
            isCustomStyle
              ? "text-text text-body1 whitespace-normal"
              : "text-text-secondary",
            singleValueClassName
          ),
        menu: () =>
          cx(
            "z-20 mt-2 rounded-input-poppers bg-surface shadow-dark-drop",
            menuClassName
          ),
        option: ({ isFocused, isSelected, label }: any) =>
          cx(
            "min-h-[40px] px-4 py-2 cursor-pointer",
            isSelected
              ? "bg-gray-200 text-text font-semibold"
              : "bg-white text-text-secondary",
            !isSelected && "hover:bg-bg-surface-hover",
            !isSelected && isFocused && "bg-bg-surface-hover",
            isCustomStyle ? "text-body1 text-text" : "",
            !isCustomStyle || options[options.length - 1]?.label === label
              ? ""
              : "border-b border-border-brand"
          ),
        placeholder: () => "text-input-text-placeholder",
        input: () => "text-text",
        valueContainer: () => "px-0",
      }),
      [
        isCustomStyle,
        controlClassName,
        menuClassName,
        options,
        hasError,
        size,
        singleValueClassName,
      ]
    );

    if (variant === "unstyled") {
      return (
        <ReactSelect
          options={options}
          value={value}
          placeholder={required ? `${placeholder}*` : placeholder}
          onChange={onChange}
          filterOption={memoizedFilterOption}
          className={cx("rounded-xl", className)}
          classNames={memoizedClassNames}
          data-cy={dataCy}
          data-testid={dataTestId}
          {...rest}
        />
      );
    }

    return (
      <div className="w-full">
        {label && (
          <label
            className={cx(
              "mb-1 block text-sm font-medium text-text-secondary",
              labelClassName
            )}
          >
            {label}
          </label>
        )}

        <ReactSelect
          options={options}
          value={value}
          placeholder={required ? `${placeholder}*` : placeholder}
          onChange={onChange}
          filterOption={memoizedFilterOption}
          className={cx("rounded-xl", className)}
          classNames={memoizedClassNames}
          data-cy={dataCy}
          data-testid={dataTestId}
          {...rest}
        />

        {error && (
          <Text className="footnote mt-1 text-text-critical">{error}</Text>
        )}

        {!error && helperText && (
          <Text className="footnote mt-1 text-text-info">{helperText}</Text>
        )}
      </div>
    );
  }
);

Select.displayName = "Select";

export type { SelectOption, SelectProps, FilterOptions };
