import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import classNames from 'clsx';

import {
  CUSTOM_LABEL_VALUE_SIZE,
  SYSTEM_LABEL_VALUE_SIZE,
  TAG_CUSTOM_TYPE,
  TAG_SYSTEM_CATEGORY_BRAND_SAFETY,
  TAG_SYSTEM_CATEGORY_IAB,
  TAG_SYSTEM_CATEGORY_TEXT,
  TAG_SYSTEM_TYPE,
} from '../../../../../../constants';
import { CustomTagsPropType, SystemTagsPropType } from '../../../../../../constants/propTypes';

import { selectedCategorySelector, selectedTagSelector, tagsOptionsSelector } from '../../../../../../redux/selectors';
import {
  createSystemTagAction,
  getCustomTagsOptionsAction,
  getSystemTagsOptionsAction,
  setStateAction,
} from '../../../../../../redux/slices';

import IabSelect from './components/IabSelect';
import { Autocomplete, Button, InputAdornment, TextField } from '@/mui/components';

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

function WithCategory(props) {
  const dispatch = useDispatch();
  const [inputValue, setInputValue] = useState('');
  const [open, setOpen] = useState(false);
  const iabRef = useRef(null);

  const selectedTag = useSelector(selectedTagSelector);
  const tagsOptions = useSelector(tagsOptionsSelector);
  const selectedCategory = useSelector(selectedCategorySelector);

  // system tags handlers
  const handleGetSystemTagOptions = (searchText = '') =>
    dispatch(
      getSystemTagsOptionsAction({
        searchText,
        category: selectedCategory.value,
      }),
    );

  const handleCreateSystemTag = (tagValue) => {
    const shouldCreateNewByApi =
      selectedCategory?.value !== TAG_SYSTEM_CATEGORY_TEXT &&
      (!selectedTag ||
        (![TAG_SYSTEM_CATEGORY_BRAND_SAFETY, TAG_SYSTEM_CATEGORY_IAB].includes(selectedCategory?.value) &&
          selectedTag.value !== tagValue));

    if (shouldCreateNewByApi) {
      dispatch(
        createSystemTagAction({
          value: tagValue.trim(),
          category: selectedCategory.value,
          callbackAfterCreate: (createdTag) => {
            props.onCreateSystemTag({
              tag: createdTag,
              category: selectedCategory,
            });
          },
        }),
      );
    } else {
      const tagForCreate =
        selectedCategory.value === TAG_SYSTEM_CATEGORY_TEXT
          ? { id: tagValue, value: tagValue, label: tagValue }
          : selectedTag;

      props.onCreateSystemTag({
        tag: tagForCreate,
        category: selectedCategory,
      });
    }
  };

  // custom tags handlers
  const handleGetCustomTagOptions = (searchText = '') =>
    dispatch(
      getCustomTagsOptionsAction({
        searchText,
        category: selectedCategory.value,
        accountId: props.accountId,
      }),
    );

  const handleCreateCustomTag = (tagValue) => {
    props.onCreateCustomTag({
      tagValue: tagValue.trim(),
      category: selectedCategory,
    });
  };

  // general handlers
  const handleSelectTag = (tag) => {
    dispatch(setStateAction({ selectedTag: tag }));

    if (selectedCategory.value !== TAG_SYSTEM_CATEGORY_IAB && tag?.label) {
      setInputValue(tag.label);
    }
  };

  const handleGetTagOptions = (searchText = inputValue, reason = '') => {
    if (selectedCategory?.group) {
      if (reason === 'reset') {
        setInputValue(searchText);
        setOpen(false);
      } else {
        const getTagOptionsFn = {
          [TAG_CUSTOM_TYPE]: handleGetCustomTagOptions,
          [TAG_SYSTEM_TYPE]: handleGetSystemTagOptions,
        }[selectedCategory.group];

        getTagOptionsFn(searchText.trim());
        setInputValue(searchText);
        setOpen(true);
      }
    }
  };

  const handleCreateTag = () => {
    const createTagFn = {
      [TAG_CUSTOM_TYPE]: handleCreateCustomTag,
      [TAG_SYSTEM_TYPE]: handleCreateSystemTag,
    }[selectedCategory.group];

    createTagFn(inputValue);

    dispatch(setStateAction({ selectedTag: null, tagsOptions: [] }));
    setInputValue('');
    setOpen(false);

    if (iabRef.current?.clear) {
      iabRef.current.clear();
    }
  };

  // clear prev options when changed category
  useEffect(() => {
    if (selectedCategory?.iconComponent) {
      setInputValue('');

      dispatch(
        setStateAction({
          selectedTag: null,
          tagsOptions: [],
        }),
      );
    }
  }, [selectedCategory]);

  // autocomplete fns
  const autocompleteBrandSafetyProps =
    selectedCategory?.value === TAG_SYSTEM_CATEGORY_BRAND_SAFETY
      ? {
          multiple: true,
          checkboxes: true,
          value: Array.isArray(selectedTag) ? selectedTag : [],
          limitTags: 1,
        }
      : {};

  const getRenderInput = (params) => {
    const isDisabled = () => {
      if (!selectedCategory) {
        return true;
      }

      if ([TAG_SYSTEM_CATEGORY_BRAND_SAFETY, TAG_SYSTEM_CATEGORY_IAB].includes(selectedCategory.value)) {
        return !selectedTag?.length;
      }

      if (!params.inputProps.value) {
        return true;
      }

      const tagsOptionsFlat = (tagsOptions || [])
        .filter((tag) => tag.label.trim().toLowerCase() !== selectedTag?.label?.trim()?.toLowerCase())
        .map((tag) => tag.label);

      const currentAppliedTagsFlat =
        selectedCategory.group === TAG_SYSTEM_TYPE
          ? props.systemTags.filter((tag) => tag.type === selectedCategory.value.toLowerCase()).map((tag) => tag.text)
          : props.customTags.filter((tag) => tag.labelId === selectedCategory.id).map((tag) => tag.value);

      const tags = [...tagsOptionsFlat, ...currentAppliedTagsFlat];

      return tags.some((tag) => tag.toLowerCase() === params.inputProps.value.trim().toLowerCase());
    };

    return (
      <TextField
        {...params}
        size="small"
        variant="outlined"
        placeholder="Tag Name"
        inputProps={{
          ...params.inputProps,
          maxLength: selectedCategory?.group === TAG_CUSTOM_TYPE ? CUSTOM_LABEL_VALUE_SIZE : SYSTEM_LABEL_VALUE_SIZE,
        }}
        InputProps={{
          ...params.InputProps,
          classes: {
            root: classNames({
              [styles.Input]: [TAG_SYSTEM_CATEGORY_BRAND_SAFETY, TAG_SYSTEM_CATEGORY_IAB].includes(
                selectedCategory?.value,
              )
                ? selectedTag?.length
                : params.inputProps.value,
            }),
          },
          endAdornment: (
            <InputAdornment position="end">
              {params.InputProps.endAdornment}
              <Button
                variant="contained"
                size="small"
                color="primary"
                shape="rounded"
                label="Add"
                disabled={props.disabled || isDisabled()}
                onClick={handleCreateTag}
              >
                Add
              </Button>
            </InputAdornment>
          ),
        }}
      />
    );
  };

  if (selectedCategory?.value === TAG_SYSTEM_CATEGORY_IAB) {
    return (
      <IabSelect
        ref={iabRef}
        renderInput={getRenderInput}
        tags={props.systemTags.filter((tag) => tag.type === TAG_SYSTEM_CATEGORY_IAB.toLowerCase())}
        onChange={(tag) => handleSelectTag(tag)}
      />
    );
  }

  return (
    <Autocomplete
      fullWidth
      size="small"
      freeSolo
      open={open}
      value={selectedTag}
      inputValue={inputValue}
      disabled={props.disabled || !selectedCategory}
      options={tagsOptions || []}
      optionValueKey="label"
      filterOptions={(options) => {
        const uniqOptions = options.reduce((acc, option) => {
          const isExist = acc.some((o) => o.label.toLowerCase() === option.label.toLowerCase());

          if (!isExist) {
            acc.push(option);
          }

          return acc;
        }, []);

        const filterStrategy = {
          [TAG_CUSTOM_TYPE]: (option) => {
            const isExist = props.customTags.some(
              (currentTag) =>
                currentTag.labelId === selectedCategory.id &&
                currentTag.name === selectedCategory.value &&
                currentTag.value === option.value,
            );

            return !isExist;
          },
          [TAG_SYSTEM_TYPE]: (option) => {
            const isExist = props.systemTags.some((currentTag) => currentTag.id === option.id);

            return !isExist;
          },
        }[selectedCategory.group];

        return uniqOptions.filter(filterStrategy);
      }}
      renderInput={getRenderInput}
      {...autocompleteBrandSafetyProps}
      onOpen={(e) => handleGetTagOptions(e.target?.value)}
      onInputChange={(e, searchText, reason) => handleGetTagOptions(searchText, reason)}
      onChange={(e, value) => handleSelectTag(value)}
      onClose={() => setOpen(false)}
    />
  );
}

WithCategory.propTypes = {
  // from props
  accountId: PropTypes.number.isRequired,
  customTags: CustomTagsPropType.isRequired,
  systemTags: SystemTagsPropType.isRequired,
  disabled: PropTypes.bool.isRequired,
  onCreateCustomTag: PropTypes.func.isRequired,
  onCreateSystemTag: PropTypes.func.isRequired,
};

export default WithCategory;
