import React, { useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import classNames from 'clsx';

import {
  NEGATIVE_BOOST_FILTERS_VALUE_DEFAULT,
  POSITIVE_BOOST_FILTERS_VALUE_DEFAULT,
} from '@/modules/players/Editor/constants';

import * as playerSelectors from '../../../../redux/selectors';
import { getIAB } from '@/modules/@common/iab/helpers';
import { getPlayerBoostListOptionsAction, setAction } from '@/modules/players/Editor/redux/slices';
import { autoSuggestHighlight } from '@/mui/helpers';
import { createFlatTreeMap } from '@/mui/helpers/treeView';

import { FormRow, useFormSettings } from '@/modules/@common/Form';
import { TagIabSelector, TagSelector } from '@/modules/@common/TagSelector';

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

const IAB_CATEGORY = 'IAB';

function TagsFilter() {
  const { size } = useFormSettings();
  const dispatch = useDispatch();
  const boostsTypesOptions = useSelector(playerSelectors.boostsTypesOptionsSelector);
  const boostsListOptions = useSelector(playerSelectors.boostsListOptionsSelector);
  const boosts = useSelector(playerSelectors.boostsSelector);

  const iabFlatTree = useMemo(() => createFlatTreeMap(getIAB(), { label: 'name', children: 'categories' }), []);
  const values = useMemo(() => {
    // build initial values { <type>: [] }
    const types = boostsTypesOptions.reduce((acc, boostType) => {
      acc[boostType.value] = [];
      return acc;
    }, {});

    boosts.forEach((boost) => {
      if (!types[boost.type]) {
        types[boost.type] = [];
      }

      if (boost.type === IAB_CATEGORY) {
        let tag = null;

        iabFlatTree.forEach((node) => {
          if (node.label === boost.value) {
            tag = node;
          }
        });

        types[boost.type].push({
          initialNode: { ...tag },
          label: tag.label,
          value: tag.id,
          include: boost.score > 0,
        });
      } else {
        types[boost.type].push({
          initialNode: { ...boost },
          label: boost.value,
          value: boost.value,
          include: boost.score > 0,
        });
      }
    });

    return types;
  }, [boosts, boostsTypesOptions]);

  const handleSetState = (state) => dispatch(setAction(state));

  return (
    <>
      {boostsTypesOptions.map((tagGroup) => {
        const clearAllByType = () => {
          handleSetState({
            boosts: boosts.filter((tag$) => tag$.type !== tagGroup.value),
          });
        };

        return (
          <FormRow key={tagGroup.value} label={tagGroup.label}>
            <>
              {tagGroup.value === IAB_CATEGORY ? (
                <TagIabSelector
                  size={size}
                  value={values[tagGroup.value] || []}
                  placeholder="Select tag"
                  onChange={(event, tags, reason) => {
                    if (reason === 'clear') {
                      clearAllByType();
                    } else {
                      const alreadyAdded = [];
                      const newBoosts = boosts.filter((boost) => {
                        if (boost.type !== IAB_CATEGORY) {
                          return true;
                        }
                        // order exclude/include fix
                        return tags.some((tag) => {
                          const exist = tag.label === boost.value && tag.include === boost.score > 0;

                          if (exist) {
                            alreadyAdded.push(boost.value);
                          }

                          return exist;
                        });
                      });

                      tags.forEach((tag) => {
                        if (!alreadyAdded.includes(tag.label)) {
                          newBoosts.push({
                            type: tagGroup.value,
                            value: tag.label,
                            score: tag.include
                              ? POSITIVE_BOOST_FILTERS_VALUE_DEFAULT
                              : NEGATIVE_BOOST_FILTERS_VALUE_DEFAULT,
                            taxonomyId: undefined,
                          });
                        }
                      });

                      handleSetState({
                        boosts: newBoosts,
                      });
                    }
                  }}
                />
              ) : (
                <TagSelector
                  size={size}
                  options={boostsListOptions.map((option) => ({
                    initialNode: { ...option },
                    label: option.value,
                    value: [option.label, option.value].filter(Boolean).join(':'),
                  }))}
                  getTagLabel={(tag) =>
                    tagGroup.grouped && tag.initialNode.label
                      ? `${tag.initialNode.label}:${tag.initialNode.value}`
                      : tag.initialNode.label
                  }
                  renderOption={(optionProps, option, { inputValue }) => (
                    <li
                      key={`${option.key}_${option.id}`}
                      {...optionProps}
                      className={classNames(styles.OptionRoot, optionProps.className)}
                    >
                      {autoSuggestHighlight(inputValue, option.label).map((part) => {
                        const Tag = part.highlight ? 'b' : React.Fragment;

                        return <Tag key={part.id}>{part.text}</Tag>;
                      })}
                    </li>
                  )}
                  value={values[tagGroup.value] || []}
                  placeholder="Select tag"
                  groupBy={tagGroup.grouped ? (option) => option.initialNode.label : undefined}
                  onOpen={() => {
                    dispatch(
                      getPlayerBoostListOptionsAction({
                        type: tagGroup.value,
                      }),
                    );
                  }}
                  onInputChange={(_, searchText) =>
                    dispatch(
                      getPlayerBoostListOptionsAction({
                        searchText,
                        type: tagGroup.value,
                      }),
                    )
                  }
                  onChange={(event, tags, reason) => {
                    if (reason === 'selectOption') {
                      handleSetState({
                        boosts: [
                          ...boosts,
                          ...tags
                            .filter(
                              (boost) => !boosts.some((b) => b.type === tagGroup.value && b.value === boost.value),
                            )
                            .map((tag) => ({
                              type: tagGroup.value,
                              value: tag.value,
                              score: tag.include
                                ? POSITIVE_BOOST_FILTERS_VALUE_DEFAULT
                                : NEGATIVE_BOOST_FILTERS_VALUE_DEFAULT,
                              taxonomyId: tag.initialNode.uid,
                            })),
                        ],
                      });
                    } else if (reason === 'removeOption') {
                      const newBoosts = [];

                      boosts.forEach((boost) => {
                        if (boost.type !== tagGroup.value) {
                          newBoosts.push(boost);
                        } else if (tags.some((tag) => tag.value === boost.value)) {
                          newBoosts.push(boost);
                        }
                      });
                      handleSetState({
                        boosts: newBoosts,
                      });
                    } else if (reason === 'clear') {
                      clearAllByType();
                    }
                  }}
                />
              )}
            </>
          </FormRow>
        );
      })}
    </>
  );
}

export default TagsFilter;
