import { Autocomplete, Avatar, Box, CircularProgress, createFilterOptions } from "@mui/material";
import TextField from "@mui/material/TextField";
import { makeStyles } from "@mui/styles";
import { isArray } from "lodash";
import React, { CSSProperties } from "react";

const useStyles = makeStyles(() => ({
  input: {
    minWidth: `0 !important`
  }})
);

export interface Option {
  label: string;
  value: any;
  group?: string;
  new?: boolean;
  icon?: string;
  defaultCableID?: number;
}

interface Props {
  selected?: Option | Option[] | null;
  changeSelection?: (newSelected: Option | null) => void;
  changeMulti?: (newSelected: Option[] | null) => void;
  options: Option[];
  label?: string;
  group?: boolean;
  creatable?: boolean;
  loading?: boolean;
  disabled?: boolean;
  multiple?: boolean;
  variant?: "filled" | "outlined" | "standard";
  style?: CSSProperties;
  getOptionSelected?: any;
  onChange?: (e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
  onKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => void;
}

export default function SearchSelect(props: Props) {
  const {
    options,
    changeSelection,
    changeMulti,
    selected,
    label,
    creatable,
    loading,
    group,
    disabled,
    multiple,
    variant,
    style,
    // getOptionSelected,
    onChange,
    onKeyDown
  } = props;
  const classes = useStyles();
  const filter = createFilterOptions<Option>({
    stringify: (option: Option) => option.label + option.group
  });

  const stringToOption = (s: string): Option => {
    return { value: s, label: s } as Option;
  };

  // const anyToLabel = (o: any): string => {
  //   if (o.text && o.value) {
  //     return o.text + " - " + o.value
  //   } else if (o.value) {
  //     return o.value
  //   } else if (o.label) {
  //     return o.label
  //   }
  //   return o.toString();
  // };

  const optionSelected = (newValue: string | Option | (string | Option)[] | null) => {
    if (multiple === true) {
      if (changeMulti) {
        if (Array.isArray(newValue)) {
          changeMulti(newValue.map(v => (typeof v === "string" ? stringToOption(v) : v)));
        } else {
          changeMulti(
            newValue
              ? [typeof newValue === "string" ? stringToOption(newValue) : newValue]
              : null
          );
        }
      } else {
        console.warn("SearchSelect requires changeMulti to be defined when 'multiple' is true");
      }
    } else {
      if (changeSelection) {
        if (Array.isArray(newValue)) {
          console.warn("changeSelection requires a single element but received an array");
        } else {
          changeSelection(typeof newValue === "string" ? stringToOption(newValue) : newValue);
        }
      } else {
        console.warn(
          "SearchSelect requires changeSelection to be defined when 'multiple' is false"
        );
      }
    }
  }

  return (
    <Autocomplete
      id={label + "-autocomplete"}
      value={selected === undefined ? null : selected}
      multiple={multiple}
      limitTags={2}
      autoHighlight
      disabled={disabled}
      onChange={(_, newValue) => {
        optionSelected(newValue)
      }}
      options={options.sort((a, b) => {
        let aGroup = a.group ? a.group : "";
        let bGroup = b.group ? b.group : "";
        if (bGroup > aGroup) return -1;
        if (aGroup > bGroup) return 1;
        return b.label > a.label ? -1 : 1;
      })}
      filterOptions={(options, params) => {
        const filtered = filter(options as Option[], params);

        if (creatable && params.inputValue !== "") {
          filtered.push({
            value: params.inputValue,
            label: params.inputValue,
            new: true
          });
        }

        return filtered;
      }}
      // getOptionLabel={option => {
      //   // return anyToLabel(option)
      //   // console.log(option)
      //   // console.log("Is Option: ",option instanceof Option)
      //   if (option instanceof Option) {
      //     return option.text + " - " + option.value
      //   // } else if (option.text && option.value) {

      //   } else {
      //     return anyToLabel(option)
      //   }
      // }}
      // getOptionSelected={
      //   getOptionSelected ? getOptionSelected : (o: { value: any; }, v: { value: any; }) => (o && v ? o.value === v.value : false)
      // }
      groupBy={group ? option => (option && option.group ? option.group : "") : undefined}
      renderInput={params => (
        <TextField
          {...params}
          label={label}
          variant={variant ? variant : "outlined"}
          onChange={onChange}
          onKeyDown={onKeyDown}
          InputProps={{
            ...params.InputProps,
            startAdornment:
              !isArray(selected) && selected?.icon ? <Avatar src={selected?.icon} /> : null,
            endAdornment: (
              <React.Fragment>
                {loading ? <CircularProgress color="inherit" size={20} /> : null}
                {params.InputProps.endAdornment}
              </React.Fragment>
            )
          }}
        />
      )}
      renderOption={(props, option) => {
        const { key, ...optionProps } = props;
        return (
        <Box
          key={key + ":" + option.value}
          component="li"
          sx={{ '& > img': { mr: 2, flexShrink: 0 } }}
          {...optionProps}
        >
          <Box style={{ marginTop: "auto", marginBottom: "auto" }}>
            {!isArray(option) && option?.icon ? <Avatar src={option?.icon} /> : ""}
          </Box>
          <Box style={{ marginTop: "auto", marginBottom: "auto", marginLeft: "1rem" }}>
            {option.label}
          </Box>
        </Box>
        )
      }}
      loading={loading}
      selectOnFocus
      clearOnBlur
      freeSolo={creatable}
      handleHomeEndKeys
      fullWidth
      classes={{
        input: classes.input
      }}
      style={style}
    />
  );
}
