import { Clear } from "@mui/icons-material";
import ExpandMoreOutlinedIcon from "@mui/icons-material/ExpandMoreOutlined";
import {
  Autocomplete,
  Box,
  Checkbox,
  Chip,
  CircularProgress,
  ListItemText,
  Stack,
  TextField,
} from "@mui/material";
import debounce from "lodash/debounce";
import React, { useEffect, useMemo, useState } from "react";
import { NOTIFICATION } from "../constants";
import { pushNotification } from "../utils/notification";
import { useStyles } from "./styles/multiSelectStyles";
import { getMasterData } from "../services/masterData.services";

const MultiSelect = ({
  searchDebounceTime = 500,
  maxSelections = Infinity,
  formik,
  fieldValue,
  fieldObjectValue,
  getOptionLabel,
  customErrorMessage = null,
  onError = (error) => console.error(error),
  styleForSelectorParent,
  styleForSelector,
  placeholderText = "",
  inputRef,
}) => {
  const classes = useStyles();
  const [data, setData] = useState([]);
  const [page, setPage] = useState(0);
  const [searchQuery, setSearchQuery] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const [dropdownOpen, setDropdownOpen] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setIsLoading(true);
        const response = await getMasterData();
        setData(response?.data?.data?.data);
      } catch (error) {
        onError(error);
      } finally {
        setIsLoading(false);
      }
    };
    fetchData();
  }, [searchQuery, page]);

  const debouncedSearch = useMemo(
    () =>
      debounce((value) => {
        setSearchQuery(value);
        setPage(0);
      }, searchDebounceTime),
    []
  );

  const handleToggleDropdown = (dropdownStatus) => {
    setDropdownOpen(() => dropdownStatus);
  };

  const handleOptionScroll = (event) => {
    const threshold = 100;
    const bottom =
      event.target.scrollHeight -
        event.target.scrollTop -
        event.target.clientHeight <=
      threshold;
    if (bottom && hasMore && !isLoading) {
      setPage((prevPage) => prevPage + 1);
    }
  };

  const handleChange = (selectedOptions) => {
    if (selectedOptions.length > maxSelections) {
      if (customErrorMessage) {
        pushNotification(customErrorMessage, NOTIFICATION.ERROR);
      }
      return;
    }

    let uniqueSelectedOptions = [];
    const optionMap = {};

    selectedOptions.forEach((option) => {
      if (optionMap[option.id]) {
        uniqueSelectedOptions = uniqueSelectedOptions.filter(
          (s) => s.id !== option.id
        );
        delete optionMap[option.id];
      } else {
        uniqueSelectedOptions.push(option);
        optionMap[option.id] = true;
      }
    });

    formik.setFieldValue(`${fieldValue}`, uniqueSelectedOptions);
    const newSelectedOptionsMap = {};
    uniqueSelectedOptions.forEach((option) => {
      newSelectedOptionsMap[option.id] = getOptionLabel(option);
    });
    formik.setFieldValue(`${fieldObjectValue}`, newSelectedOptionsMap);
  };

  const handleOptionDelete = (optionId) => {
    const newOptions = formik.values[fieldValue].filter(
      (option) => option.id !== optionId
    );
    formik.setFieldValue(`${fieldValue}`, newOptions);
    const newSelectedOptionsMap = { ...formik.values[fieldObjectValue] };
    delete newSelectedOptionsMap[optionId];
    formik.setFieldValue(`${fieldObjectValue}`, newSelectedOptionsMap);
  };

  return (
    <Box className={classes.main}>
      <Box
        className={`${classes.selectAndSearchField} ${styleForSelectorParent}`}
      >
        <Autocomplete
          className={`${classes.autoComplete} ${styleForSelector}`}
          freeSolo
          multiple
          disableCloseOnSelect
          disableClearable
          options={data}
          getOptionLabel={getOptionLabel}
          onOpen={() => {
            handleToggleDropdown(!dropdownOpen);
          }}
          onClose={() => {
            handleToggleDropdown(false);
          }}
          value={formik?.values[fieldValue]}
          open={dropdownOpen}
          onInputChange={(event, value) => {
            debouncedSearch(value);
            setDropdownOpen(true);
          }}
          onChange={(event, newValue) => handleChange(newValue)}
          renderOption={(props, option) => (
            <li {...props}>
              <Checkbox
                style={{ marginRight: 8 }}
                checked={formik.values[fieldValue]?.some(
                  (selectedOption) => selectedOption.id === option.id
                )}
              />
              <ListItemText primary={getOptionLabel(option)} />
            </li>
          )}
          renderInput={(params) => (
            <TextField
              {...params}
              variant="outlined"
              onChange={(event) => {
                event.preventDefault();
                debouncedSearch(event.target.value.trim());
              }}
              onKeyDown={(event) => {
                if (event.key === "Backspace") {
                  event.stopPropagation();
                }
              }}
              InputProps={{
                ...params.InputProps,
                type: "search",
                endAdornment: (
                  <>
                    {isLoading ? (
                      <CircularProgress color="inherit" size={20} />
                    ) : (
                      <ExpandMoreOutlinedIcon
                        onClick={() => setDropdownOpen(!dropdownOpen)}
                        className={`${classes.dropDownArrow} ${
                          classes.hoverPointer
                        } ${
                          dropdownOpen
                            ? classes.rotate180Deg
                            : classes.rotate0Deg
                        }`}
                      /> // Toggle dropdown on click
                    )}
                    {params.InputProps.endAdornment}
                  </>
                ),
              }}
              inputRef={inputRef}
              error={Boolean(
                formik?.errors[fieldValue] && formik?.touched[fieldValue]
              )}
              helperText={
                formik?.errors[fieldValue] && formik?.touched[fieldValue]
                  ? formik?.errors[fieldValue]
                  : null
              }
              placeholder={placeholderText}
            />
          )}
          renderTags={() => (
            <div>{/* {`${formik.values[fieldValue].length} selected`} */}</div>
          )}
          ListboxProps={{
            onScroll: handleOptionScroll,
          }}
        />
        {/* {fieldName && (
          <Grid className={classes.autoCompleteText} item>
            {formik.values[fieldValue]?.length}{' '}
            {formik.values[fieldValue]?.length > 1
              ? fieldName && `${fieldName + 's'}`
              : fieldName}{' '}
            Selected
          </Grid>
        )} */}
      </Box>
      <Box>
        <Stack className={classes.chipOuter}>
          {formik?.values[fieldValue]?.map((option) => (
            <Chip
              className={classes.chip}
              key={option.id}
              label={getOptionLabel(option)}
              onDelete={() => handleOptionDelete(option.id)}
              deleteIcon={<Clear />}
            />
          ))}
        </Stack>
      </Box>
    </Box>
  );
};

export default MultiSelect;
