import type { ReactNode } from "react";

import MenuItem from "@mui/material/MenuItem";
import Select from "@mui/material/Select";
import Typography from "@mui/material/Typography";
import { useTheme } from "@mui/material/styles";
import type { SelectChangeEvent, SelectProps } from "@mui/material/Select";
import type { SxProps, Theme } from "@mui/material/styles";

import {
  getFormSelectMenuProps,
  getFormSelectSx,
} from "@/components/ui/form";

export type AppSelectOption<TData = unknown> = {
  data?: TData;
  disabled?: boolean;
  label: string;
  value: string;
};

export type AppSelectProps<TData = unknown> = Omit<
  SelectProps<string>,
  "onChange" | "renderValue" | "value"
> & {
  onChange: (value: string) => void;
  menuOptions?: AppSelectOption<TData>[];
  options: AppSelectOption<TData>[];
  placeholder?: string;
  renderOption?: (option: AppSelectOption<TData>) => ReactNode;
  renderSelectedValue?: (option?: AppSelectOption<TData>) => ReactNode;
  showPlaceholderOption?: boolean;
  sx?: SxProps<Theme>;
  value: string;
};

function getSxArray(sx?: SxProps<Theme>) {
  if (!sx) return [];

  return Array.isArray(sx) ? sx : [sx];
}

export function AppSelect<TData = unknown>({
  onChange,
  options,
  placeholder = "Select",
  renderOption,
  renderSelectedValue,
  showPlaceholderOption = true,
  sx,
  value,
  MenuProps,
  menuOptions,
  ...props
}: AppSelectProps<TData>) {
  const theme = useTheme();
  const selectedOption = options.find((option) => option.value === value);
  const visibleOptions = menuOptions ?? options;

  function handleChange(event: SelectChangeEvent<string>) {
    onChange(event.target.value);
  }

  function renderValue() {
    if (renderSelectedValue) {
      return renderSelectedValue(selectedOption);
    }

    return selectedOption?.label ?? (
      <Typography sx={{ fontSize: 12, color: theme.palette.text.secondary }}>
        {placeholder}
      </Typography>
    );
  }

  return (
    <Select
      fullWidth
      size="small"
      displayEmpty
      value={value}
      onChange={handleChange}
      renderValue={renderValue}
      sx={[getFormSelectSx(theme), ...getSxArray(sx)]}
      MenuProps={MenuProps ?? getFormSelectMenuProps(theme)}
      {...props}
    >
      {showPlaceholderOption ? (
        <MenuItem value="">
          <Typography
            sx={{ fontSize: 12, color: theme.palette.text.secondary }}
          >
            {placeholder}
          </Typography>
        </MenuItem>
      ) : null}

      {visibleOptions.map((option) => (
        <MenuItem
          key={option.value}
          value={option.value}
          disabled={option.disabled}
        >
          {renderOption ? renderOption(option) : option.label}
        </MenuItem>
      ))}
    </Select>
  );
}
