import { useEffect, useState } from 'react';
import { useFormContext } from 'react-hook-form';

import { spyIfWritingTaggedUser, tagNewUser } from 'tag-users';
import Container from '@material-hu/mui/Container';

import useSnackbar from '@material-hu/components/design-system/Snackbar';

import { type Updater } from 'src/types/queries';
import { ActionTagUser, type TaggedUser, type User } from 'src/types/user';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';
import { isFirefox } from 'src/utils/platform';
import {
  getFullName,
  getTaggedUserData,
  getTaggedUserPosition,
  getTaggedUsers,
  putCaretInCorrectPosition,
} from 'src/utils/userUtils';

import PeopleList from 'src/components/dashboard/people/PeopleList';
import FormTextField, {
  type FormTextFieldProps,
} from 'src/components/FormInputs/FormTextField';
import Highlighter from 'src/components/Highlighter';

export type FormTextFieldTagUsersProps = FormTextFieldProps & {
  isSubmitting: boolean;
  taggedUsers: TaggedUser[];
  name: string;
  onChangeTaggedUsers: (updater: Updater<TaggedUser[]>) => void;
  defaultBody?: string;
  placeholder?: string;
  InputProps?: {
    id?: string;
    endAdornment?: JSX.Element;
    disableUnderline?: boolean;
    sx?: object;
  };
  isFocus?: boolean;
  replyUser?: User;
  onDeleteUserReply?: () => void;
  stylesHighlighter?: any;
  withCustomPeopleList?: boolean;
  CustomPeopleList?: any;
};

const defaultCaretPositionData = {
  user: null,
  tagUserStartPosition: 0,
  action: '',
};

export const FormTextFieldTagUsers = ({
  isSubmitting,
  taggedUsers,
  onChangeTaggedUsers,
  name,
  defaultBody,
  placeholder,
  InputProps,
  isFocus = false,
  variant = 'outlined',
  replyUser = null,
  onDeleteUserReply,
  stylesHighlighter,
  withCustomPeopleList = false,
  CustomPeopleList,
  ...fieldProps
}: FormTextFieldTagUsersProps) => {
  const { t } = useTranslation(['post']);
  const { enqueueSnackbar } = useSnackbar();

  const [isError, setIsError] = useState(false);
  const [tagUser, setTagUser] = useState(false);
  const [tagUserStartPosition, setTagUserStartPosition] = useState(0);
  const [focused, setFocused] = useState(isFocus);
  const [userSearch, setUserSearch] = useState('');
  const [messageBodyWithoutLastTag, setMessageBodyWithoutLastTag] =
    useState('');
  const [addUserTag, setAddUserTag] = useState(false);
  const [selectedText, setSelectedText] = useState('');
  const [startPositionSelectedText, setStartPositionSelectedText] = useState(0);
  const [endPositionSelectedText, setEndPositionSelectedText] = useState(0);
  const [lastKey, setLastKey] = useState(null);
  const [caretPositionData, setCaretPositionData] = useState(
    defaultCaretPositionData,
  );

  const { setValue, getValues, reset, watch, setFocus } = useFormContext();

  const newText = watch(name);
  const browserFirefoxFlag = isFirefox();
  const input = document.getElementById(InputProps.id) as HTMLInputElement;

  useEffect(() => {
    if (isError) {
      enqueueSnackbar({ title: t('ERROR_GENERAL'), variant: 'error' });
    }
  }, [isError]);

  useEffect(() => {
    if (!input) return;

    if (defaultBody) {
      setFocus(name);
      input.setSelectionRange(defaultBody.length, defaultBody.length);
    } else if (replyUser) {
      const userName = getFullName(replyUser);
      setFocus(name);
      input.setSelectionRange(userName.length + 1, userName.length + 1);
    }
  }, [input, defaultBody]);

  useEffect(() => {
    if (isSubmitting) {
      setTagUser(false);
      setTagUserStartPosition(0);
      setFocused(false);
      setUserSearch('');
      onChangeTaggedUsers([]);
      setMessageBodyWithoutLastTag('');
    }
  }, [isSubmitting, onChangeTaggedUsers]);

  useEffect(() => {
    if (defaultBody) {
      setMessageBodyWithoutLastTag(defaultBody);
    }
  }, [defaultBody]);

  useEffect(() => {
    if (taggedUsers.length > 0 && newText) {
      taggedUsers.forEach(async tag => {
        const userId = tag.type.user.id;

        const user = await getTaggedUserData(userId);
        if (!user) {
          setIsError(true);
          return;
        }

        if (user.deleted) {
          handleDeleteTagUser(userId);
          return;
        }

        const position = getTaggedUserPosition(user, newText);
        if (position >= 0) {
          changeTaggedUserStartPosition(userId, position);
        }
      });
    }

    if (caretPositionData.user) {
      putCaretInCorrectPosition(
        caretPositionData,
        input,
        startPositionSelectedText,
        lastKey,
        selectedText,
      );

      setCaretPositionData(defaultCaretPositionData);
    }
  }, [taggedUsers.length, newText, caretPositionData.user]);

  const putSelectedDataWithDefault = () => {
    setSelectedText('');
    setStartPositionSelectedText(0);
    setEndPositionSelectedText(0);
  };

  useEffect(() => {
    const textarea = document.querySelector(`#${InputProps.id}`);
    const getSelectionOfInput = event => {
      if (event.target.value !== '') {
        const selection = event.target.value.substring(
          event.target.selectionStart,
          event.target.selectionEnd,
        );
        setSelectedText(selection);
        setStartPositionSelectedText(event.target.selectionStart);
        setEndPositionSelectedText(event.target.selectionEnd);
      }
    };

    textarea.addEventListener('select', getSelectionOfInput);

    () => {
      textarea.removeEventListener('select', getSelectionOfInput);
    };
  }, []);

  const filterTaggedUsers = (users: User[]) =>
    users?.filter(
      user => !taggedUsers.some(tag => tag.type.user.id === user.id),
    );

  const handleDeleteTagUser = (userId: number) =>
    onChangeTaggedUsers(prevTaggedUsers =>
      prevTaggedUsers.filter(tag => tag.type.user.id !== userId),
    );

  const addTaggedUser = (tag: TaggedUser) =>
    onChangeTaggedUsers(prevTaggedUsers => [...prevTaggedUsers, tag]);

  const changeTaggedUserStartPosition = (
    userId: number,
    newStartPosition: number,
  ) =>
    onChangeTaggedUsers(prevTaggedUsers =>
      prevTaggedUsers.map(user =>
        user.type.user.id === userId
          ? { ...user, start: newStartPosition }
          : user,
      ),
    );

  const deleteTaggedUser = async (userId: number) => {
    const user = await getTaggedUserData(userId);
    if (!user) {
      setIsError(true);
      return;
    }

    const position = getTaggedUserPosition(user, newText);

    setCaretPositionData({
      user,
      tagUserStartPosition: position,
      action: ActionTagUser.DELETETAGUSER,
    });

    handleDeleteTagUser(userId);

    if (replyUser) {
      onDeleteUserReply();
    }
  };

  const handleSelect = (user: User) => {
    tagNewUser({
      user,
      setTagUser,
      setUserSearch,
      taggedUsers,
      messageBodyWithoutLastTag,
      setMessageBodyWithoutLastTag,
      onChangeText: text => setValue(name, text),
      tagUserStartPosition,
      addTaggedUser,
      changeTaggedUserStartPosition,
      isWeb: true,
    });
    setCaretPositionData({
      user,
      tagUserStartPosition,
      action: ActionTagUser.ADDUSER,
    });
  };

  useEffect(() => {
    if (replyUser) {
      reset();
      setMessageBodyWithoutLastTag('');
      setAddUserTag(true);
    }
  }, [replyUser]);

  useEffect(() => {
    if (addUserTag) {
      handleSelect(replyUser);
      onChangeTaggedUsers(getTaggedUsers([replyUser]));
      setAddUserTag(false);
    }
  }, [addUserTag]);

  const handleOnChange = e => {
    if (!e.target.value) {
      setUserSearch('');
      setTagUser(false);
      onChangeTaggedUsers([]);
    }

    spyIfWritingTaggedUser({
      text: e.target.value,
      tagUser,
      setTagUser,
      value: getValues(name),
      userSearch,
      setUserSearch,
      taggedUsers,
      messageBodyWithoutLastTag,
      onChangeText: text => setValue(name, text),
      setMessageBodyWithoutLastTag,
      setTagUserStartPosition,
      changeTaggedUserStartPosition,
      deleteTaggedUser,
      selectedText,
      startPositionSelectedText,
      endPositionSelectedText,
      lastKey,
      browserFirefoxFlag,
    });
  };

  const handleOnKeyDown = event => {
    let textSelectedOnInput;
    if (browserFirefoxFlag) {
      textSelectedOnInput = (
        document.activeElement as HTMLInputElement
      ).value.substring(
        (document.activeElement as HTMLInputElement).selectionStart,
        (document.activeElement as HTMLInputElement).selectionEnd,
      );
    } else {
      textSelectedOnInput = window.getSelection().toString();
    }
    if (selectedText && !textSelectedOnInput) {
      putSelectedDataWithDefault();
    }
    setLastKey(event.key);
    fieldProps.onKeyDown?.(event);
  };

  return (
    <Container sx={{ p: '0 !important', position: 'relative' }}>
      <Highlighter
        textAreaRef={InputProps.id}
        taggedUsers={taggedUsers}
        styles={stylesHighlighter}
      />
      <FormTextField
        {...fieldProps}
        name={name}
        ariaLabel={t('post:message_body')}
        placeholder={placeholder || t('post:feed_create_post')}
        size="small"
        variant={variant}
        multiline
        disabled={isSubmitting || isError}
        onFocus={() => setFocused(true)}
        onChange={handleOnChange}
        onKeyDown={handleOnKeyDown}
        InputProps={InputProps}
        inputProps={{ maxLength: 10000 }}
      />
      {focused && tagUser && (
        <Container
          sx={{
            height: '320px',
            p: '0 !important',
            mb: -6,
            width: 'inherit',
            mx: '0 !important',
          }}
        >
          {withCustomPeopleList ? (
            <CustomPeopleList
              handleSelect={handleSelect}
              query={userSearch}
              select={filterTaggedUsers}
            />
          ) : (
            <PeopleList
              listContainerStyle={{ backgroundColor: '#f4f5f7' }}
              listSubHeaderStyle={{ backgroundColor: '#f4f5f7' }}
              limit={4}
              handleSelect={handleSelect}
              query={userSearch}
              select={filterTaggedUsers}
              formTextField
            />
          )}
        </Container>
      )}
    </Container>
  );
};

export default FormTextFieldTagUsers;
