import _ from 'lodash';
import i18next from 'i18next';
import PropTypes from 'prop-types';
import React, { useState, forwardRef, Ref, useEffect } from 'react';

import IconFilter from '../images/icon-selector-filter.svg';
import IconFilterBlue from '../images/icon-selector-filter-blue.svg';

import InputNumber from '../InputNumber';
import RadioButton from '../RadioButton';

import iconCheckMarkBlue from '../images/icon-check-mark-blue.svg';

import {
  Container,
  FilterIcon,
  TitleContainer,
  Title,
  FilterContainer,
  Content,
  RowContainer,
  RowLabel,
  Icon,
  ActionContainer,
  ItemSelectionList,
  ItemSelectionListRow,
} from './styledComponents';

import { getSelectorFilters } from './constants';
import { Props } from './interfaces';

const renderItemSelector = (
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  list: any[],
  filterPropertyKey: string,
  handleSelectItemList: Function
) => {
  const orderedList = _.orderBy(
    list,
    [
      (item) => {
        if (item.id === 'GENERAL_ALL') {
          return -1;
        }

        return (item[filterPropertyKey] || '').toLowerCase();
      },
    ],
    ['asc']
  );

  return (
    <ItemSelectionList>
      {orderedList.map((item) => (
        <ItemSelectionListRow
          key={item.id}
          onClick={() => handleSelectItemList(item, filterPropertyKey)}
          selected={item.selected}
        >
          {item.name}
          {item.selected && (
            <Icon src={iconCheckMarkBlue} alt="selected-item" />
          )}
        </ItemSelectionListRow>
      ))}
    </ItemSelectionList>
  );
};

const renderContent = (
  type: string,
  handleCriterionSelection: Function,
  selectedCriterionId: string,
  value: number | string,
  limitValues: {
    minValue: number | string;
    maxValue: number | string;
  },
  handleInputChange
) => {
  const selectorFilters = getSelectorFilters();

  if (!Object.prototype.hasOwnProperty.call(selectorFilters, type)) {
    return null;
  }

  return (
    <>
      {selectorFilters[type].content.map((criterion) => (
        <RowContainer key={criterion.id}>
          <RowLabel
            onClick={() =>
              handleCriterionSelection(criterion.id, criterion.type)
            }
          >
            <RadioButton
              value={criterion.id}
              selected={selectedCriterionId}
              size="small"
            />
            <p>{criterion.name}</p>
          </RowLabel>
          {selectedCriterionId === criterion.id && (
            <InputNumber
              display={criterion.type}
              value={value}
              limitValues={limitValues}
              onChange={handleInputChange}
              min={-999999}
            />
          )}
        </RowContainer>
      ))}
    </>
  );
};

const SelectorFilter = forwardRef(
  (props: Props, ref: Ref<HTMLDivElement>): JSX.Element => {
    const {
      type,
      itemList,
      filterId,
      selectedFilter,
      filterPropertyKey,
      handleFilterSelection,
      onFilterChange,
      isFilterActive,
      languageCode,
      customPosition,
    } = props;

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const [listToDisplay, setListToDisplay] = useState<any[]>([]);

    const [selectedCriterionId, setSelectedCriterionId] = useState('');

    const [value, setValue] = useState<string | number>(0);
    const [limitValues, setLimitValues] = useState<{
      minValue: number | string;
      maxValue: number | string;
    }>({
      minValue: 0,
      maxValue: 0,
    });

    useEffect(() => {
      if (itemList && itemList.length && !listToDisplay.length) {
        setListToDisplay([
          {
            id: 'GENERAL_ALL',
            name: i18next.t('GENERAL_ALL'),
            selected: false,
          },
          ...itemList,
        ]);
      }
    }, [itemList, listToDisplay]);

    useEffect(() => {
      if (!isFilterActive) {
        if (listToDisplay.length) {
          const updatedListToDisplay = listToDisplay.map((item) => ({
            ...item,
            selected: false,
          }));
          setListToDisplay(updatedListToDisplay);
        }

        if (selectedCriterionId) {
          setValue(0);
          setLimitValues({
            minValue: 0,
            maxValue: 0,
          });
          setSelectedCriterionId('');
        }
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [isFilterActive]);

    useEffect(() => {
      if (type === 'string' && listToDisplay && listToDisplay.length) {
        const selectedItems = listToDisplay.filter((item) => item.selected);

        onFilterChange(
          `string-selector-filter-${filterPropertyKey}`,
          getSelectorFilters().string.content[0].doFilter,
          selectedItems
        );
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [type, listToDisplay]);

    useEffect(() => {
      i18next.changeLanguage(languageCode);
    }, [languageCode]);

    const isFilterSelected = selectedFilter === filterId;

    const handleCriterionSelection = (
      criterionId: string,
      criterionType: string
    ) => {
      setSelectedCriterionId(
        criterionId !== selectedCriterionId ? criterionId : ''
      );

      if (criterionType === 'single') {
        setValue(0);
      } else {
        setLimitValues({ minValue: 0, maxValue: 0 });
      }
    };

    const handleSelectItemList = (selectedItem) => {
      if (selectedItem.id === 'GENERAL_ALL') {
        const areAllItemsSelected = listToDisplay.every((item) => {
          if (item.id === 'GENERAL_ALL') {
            return true;
          }

          return item.selected;
        });

        const updatedListToDisplay = listToDisplay.map((item) => ({
          ...item,
          selected: !areAllItemsSelected,
        }));

        setListToDisplay(updatedListToDisplay);

        return;
      }

      const updatedListToDisplay = listToDisplay.map((item) => {
        if (item.name === selectedItem.name) {
          return {
            ...item,
            selected: !item.selected,
          };
        }

        return item;
      });

      const areAllUpdatedItemsSelected = updatedListToDisplay.every((item) => {
        if (item.id === 'GENERAL_ALL') {
          return true;
        }

        return item.selected;
      });

      setListToDisplay(
        updatedListToDisplay.map((item) => {
          if (item.id === 'GENERAL_ALL') {
            return {
              ...item,
              selected: areAllUpdatedItemsSelected,
            };
          }

          return item;
        })
      );
    };

    const handleFilter = () => {
      // get values according to type of the chosen filter criterion
      const filterValues =
        selectedCriterionId === 'between' ? limitValues : value;

      const selectorFilters = getSelectorFilters();

      // get filter criterion definition
      const filterCriterion = selectorFilters[type].content.find(
        (criterion) => criterion.id === selectedCriterionId
      );

      // update filter
      if (filterCriterion) {
        onFilterChange(filterId, filterCriterion.doFilter, filterValues);
      } else {
        onFilterChange(filterId, null, null);
      }

      handleFilterSelection(filterId);
    };

    const handleInputChange = (e, id: string) => {
      const formattedValue = !Number.isNaN(parseInt(e.target.value, 10))
        ? parseInt(e.target.value, 10)
        : null;

      if (formattedValue === null) {
        return;
      }

      if (id === 'min') {
        setLimitValues({ ...limitValues, ...{ minValue: formattedValue } });
      } else if (id === 'max') {
        setLimitValues({ ...limitValues, ...{ maxValue: formattedValue } });
      } else {
        setValue(formattedValue);
      }
    };

    return (
      <Container ref={ref}>
        <FilterIcon
          src={isFilterActive ? IconFilterBlue : IconFilter}
          alt="icon-filter"
          onClick={(e) => {
            e.stopPropagation();
            handleFilterSelection(filterId);
          }}
          onMouseEnter={(e) =>
            !isFilterActive && e.target.setAttribute('src', IconFilterBlue)
          }
          onMouseLeave={(e) =>
            !isFilterActive && e.target.setAttribute('src', IconFilter)
          }
        />
        {isFilterSelected && (
          <FilterContainer
            fitContent={type === 'string'}
            onClick={(e) => e.stopPropagation()}
            customPosition={customPosition}
          >
            {type === 'string' &&
              renderItemSelector(
                listToDisplay,
                filterPropertyKey,
                handleSelectItemList
              )}
            {type !== 'string' && (
              <>
                <TitleContainer>
                  <Title>
                    {i18next.t('COMPONENT_VALUE_SELECTOR_FILTER_SELECTION')}
                  </Title>
                </TitleContainer>
                <Content>
                  {renderContent(
                    type,
                    handleCriterionSelection,
                    selectedCriterionId,
                    value,
                    limitValues,
                    handleInputChange
                  )}
                </Content>
                <ActionContainer onClick={handleFilter}>
                  <div>{i18next.t('GENERAL_VALIDATE')}</div>
                </ActionContainer>
              </>
            )}
          </FilterContainer>
        )}
      </Container>
    );
  }
);

SelectorFilter.propTypes = {
  filterId: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
    .isRequired,
  type: PropTypes.string.isRequired,
  handleFilterSelection: PropTypes.func.isRequired,
  onFilterChange: PropTypes.func.isRequired,
  selectedFilter: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.object,
  ]),
  languageCode: PropTypes.string,
  // eslint-disable-next-line react/forbid-prop-types
  itemList: PropTypes.arrayOf(PropTypes.any),
  filterPropertyKey: PropTypes.string.isRequired,
  isFilterActive: PropTypes.bool,
  customPosition: PropTypes.string,
};

SelectorFilter.defaultProps = {
  itemList: [],
  languageCode: 'fr',
  selectedFilter: null,
  isFilterActive: false,
  customPosition: '-135',
};

export default SelectorFilter;
