import React, { useEffect, useState } from 'react';

import type { GeneralSizeProp } from '@/mui/types';

import { getIAB } from '@/modules/@common/iab/helpers';
import { iabCategoriesSelector } from '@/modules/feeds/Editor/redux/selectors';
import { setAction } from '@/modules/feeds/Editor/redux/slices';
import { createFlatTreeMap, getAggregateSelectedIds, NodeType } from '@/mui/helpers/treeView';

import { useFormSettings } from '@/modules/@common/Form';
import { useAppDispatch, useAppSelector } from '@/modules/@common/store/hooks';
import { Autocomplete, TextField, TreeView } from '@/mui/components';

import styles from './IabCategories.module.scss';

type PropTypes = {
  disabled?: boolean;
};

type SelectedFnType = (node: NodeType) => unknown;

function IabCategories({ disabled = false }: PropTypes) {
  const dispatch = useAppDispatch();
  const { size } = useFormSettings();
  const iabCategories = useAppSelector(iabCategoriesSelector);
  const [open, setOpen] = useState(false);
  const [search, setSearch] = useState('');
  const [flatTree, setFlatTree] = useState(
    createFlatTreeMap(getIAB() as NodeType[], {
      label: 'name',
      children: 'categories',
    }),
  );
  const [autoCompleteValue, setAutoCompleteValue] = useState(getAggregateSelectedIds(flatTree, true));

  const updateTreeState = (selectedFn: SelectedFnType) => {
    const copiedMap = new Map();

    let hasChanges = false;

    flatTree.forEach((node) => {
      const selected = selectedFn(node);

      if (selected !== node.selected) {
        hasChanges = true;
      }

      copiedMap.set(node.id, {
        ...node,
        selected,
      });
    });

    setFlatTree((prev) => (hasChanges ? copiedMap : prev));

    if (hasChanges) {
      const selected = getAggregateSelectedIds(copiedMap);
      setAutoCompleteValue(selected);
      dispatch(setAction({ iabCategories: JSON.stringify(selected) }));
    }
  };

  const clear = () => {
    setAutoCompleteValue([]);
    setSearch('');
    setOpen(false);
    dispatch(setAction({ iabCategories: JSON.stringify([]) }));
  };

  useEffect(() => {
    if (!autoCompleteValue.length) {
      try {
        const values = JSON.parse(iabCategories);
        updateTreeState((node) => values.includes(node.id));
      } catch (e) {
        console.warn(e);
      }
    }
  }, [iabCategories]);

  return (
    <Autocomplete
      disabled={disabled}
      open={open}
      fullWidth
      size={size as GeneralSizeProp}
      multiple
      limitTags={10}
      inputValue={search}
      value={autoCompleteValue}
      getOptionLabel={(id) => flatTree.get(id).label}
      optionValueKey="id"
      options={[]}
      renderInput={(params) => <TextField {...params} value="" variant="outlined" placeholder="Select IAB" />}
      classes={{
        noOptions: styles.NoOptionsWrapper,
      }}
      noOptionsText={
        <TreeView
          flatTree={flatTree}
          searchText={search}
          multiSelect
          autoSuggest
          onNodeSelect={(event, nodeIds) => {
            updateTreeState((sourceNode: NodeType) => nodeIds.includes(sourceNode.id));
          }}
        />
      }
      onChange={(event, autocompleteValues, reason, value) => {
        if (reason === 'removeOption') {
          const targetNode = flatTree.get(value!.option);

          updateTreeState(
            (sourceNode) =>
              sourceNode.selected &&
              sourceNode.id !== targetNode.id &&
              !targetNode.childrenIds.includes(sourceNode.id) &&
              !targetNode.parentPath.includes(sourceNode.id),
          );
        } else if (reason === 'clear') {
          clear();
        }
      }}
      onInputChange={(event, value) => {
        setSearch(value);
      }}
      onOpen={() => {
        setAutoCompleteValue(getAggregateSelectedIds(flatTree, true));
        setTimeout(() => setOpen(true), 0);
      }}
      onClose={() => {
        setOpen(false);
      }}
    />
  );
}

export default IabCategories;
