import React, { useEffect, useMemo, useState } from 'react';
import type { AutocompleteChangeReason } from '@mui/material';

import { SIZE_MEDIUM, SIZE_SMALL } from '@/mui/constants';

import { ShapeProp } from '@/mui/types';

import { getIAB } from '@/modules/@common/iab/helpers';
import { createFlatTreeMap, getAggregateSelectedIds, NodeType, TreeMapperType } from '@/mui/helpers/treeView';

import { Autocomplete, TextField, TreeView } from '@/mui/components';

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

const treeMapper = {
  label: 'name',
  children: 'categories',
};

type Props = {
  size?: typeof SIZE_SMALL | typeof SIZE_MEDIUM;
  value?: string[];
  shape?: ShapeProp;
  placeholder?: string;
  onChange: (
    event: React.SyntheticEvent,
    option: unknown | unknown[] | object[],
    reason: AutocompleteChangeReason | null,
  ) => void;
  onInputChange?: (event: React.SyntheticEvent, query: string) => void;
  onOpen?: () => void;
  onClose?: () => void;
};

function IabSelector({
  size = 'medium',
  value = [],
  shape,
  placeholder,
  onChange,
  onInputChange,
  onOpen,
  onClose,
  ...restProps
}: Props) {
  const [searchText, setSearchText] = useState('');
  const [flatTree, setFlatTree] = useState(
    createFlatTreeMap(getIAB() as NodeType[], treeMapper as TreeMapperType, value),
  );

  useEffect(() => {
    setFlatTree(createFlatTreeMap(getIAB() as NodeType[], treeMapper as TreeMapperType, value));
  }, [value]);

  const tagList = useMemo(
    () =>
      getAggregateSelectedIds(flatTree).map((nodeId) => {
        const node = flatTree.get(nodeId);

        return {
          label: node.label,
          value: node.id,
          id: node.id,
          include: true,
        };
      }),
    [flatTree],
  );

  return (
    <Autocomplete
      onOpen={onOpen}
      onClose={onClose}
      {...restProps}
      size={size}
      value={tagList}
      multiple
      filterOptions={(x) => x}
      isOptionEqualToValue={() => false}
      inputValue={searchText}
      options={[]}
      optionLabelKey="label"
      optionValueKey="value"
      classes={{
        noOptions: styles.NoOptions,
      }}
      onChange={(event, tags, reason) => {
        setFlatTree((prevState) => {
          const hasChanges = false;
          const copiedMap = new Map(prevState);
          const tags$ = tags as Array<{ id: string }>;

          copiedMap.forEach((node) => {
            copiedMap.set(node.id, {
              ...node,
              selected: tags$.some(({ id }) => node.id === id),
            });
          });

          onChange(
            event,
            [
              ...getAggregateSelectedIds(copiedMap).map((nodeId) => {
                const node = copiedMap.get(nodeId);

                return {
                  ...node,
                };
              }),
            ],
            reason,
          );

          return hasChanges ? copiedMap : prevState;
        });
      }}
      onInputChange={(event, query) => {
        setSearchText(query);

        if (onInputChange) {
          onInputChange(event, query);
        }
      }}
      renderInput={(params) => <TextField {...params} shape={shape} size={size} placeholder={placeholder} />}
      noOptionsText={
        <TreeView
          flatTree={flatTree}
          onNodeSelect={(event, nodeIds) => {
            const primaryTree = flatTree;

            const copiedMap = new Map();

            primaryTree.forEach((node) => {
              copiedMap.set(node.id, {
                ...node,
                selected: nodeIds.includes(node.id),
              });
            });

            setFlatTree(copiedMap);

            onChange(
              event,
              [
                ...getAggregateSelectedIds(copiedMap).map((nodeId) => {
                  const node = copiedMap.get(nodeId);

                  return {
                    ...node,
                  };
                }),
              ],
              null,
            );
          }}
          searchText={searchText}
        />
      }
    />
  );
}

export default IabSelector;
