import { type FC, type KeyboardEvent, useMemo, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { type UseMutationResult } from 'react-query';

import { IconPaperclip, IconSend } from '@material-hu/icons/tabler';
import IconButton from '@material-hu/mui/IconButton';
import InputAdornment from '@material-hu/mui/InputAdornment';
import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import Tooltip from '@material-hu/mui/Tooltip';

import HuAvatar from '@material-hu/components/design-system/Avatar';

import { MAX_ATTACHMENTS_B } from 'src/constants/posts';
import { useAuth } from 'src/contexts/JWTContext';
import { uploadAllImages } from 'src/services/attachments';
import {
  type Attachment,
  type FormFile as FormFileType,
} from 'src/types/attachments';
import { type PostCommentPayload } from 'src/types/comments';
import { type Updater } from 'src/types/queries';
import { type TaggedUser } from 'src/types/user';
import { isValidFilesSize } from 'src/utils/attachments';
import { getAttachment } from 'src/utils/files';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { getFullName, getInitials } from 'src/utils/userUtils';

import { AttachmentsList, AttachmentsSize } from 'src/components/attachment';
import AttachmentsAdd from 'src/components/attachment/AttachmentsAdd';
import ReactionAdd from 'src/components/dashboard/reactions/ReactionAdd';
import FormTextFieldTagUsers from 'src/components/FormInputs/FormTextFieldTagUsers';

import { COMMENT_ADD_INPUT_ID } from '../constants';

export type AddCommentType = {
  maxAttachmentsBytes?: number;
  canAddImages?: boolean;
  postMutation: UseMutationResult<any, unknown, PostCommentPayload, unknown>;
  containerElement?: HTMLDivElement | null;
};

const AddComment: FC<AddCommentType> = props => {
  const {
    maxAttachmentsBytes = MAX_ATTACHMENTS_B,
    postMutation,
    canAddImages = true,
    containerElement,
  } = props;
  const [taggedUsers, setTaggedUsers] = useState<TaggedUser[]>([]);
  const [images, setImages] = useState<FormFileType[]>([]);
  const { user: loggedUser } = useAuth();
  const { t } = useLokaliseTranslation('livestream');
  const theme = useTheme();

  const form = useForm({
    defaultValues: {
      body: '',
    },
  });

  const {
    handleSubmit,
    watch,
    reset,
    setValue,
    formState: { isSubmitting },
  } = form;

  const isValidAttachments = (): boolean => {
    if (maxAttachmentsBytes === null) return true;

    return isValidFilesSize(images, maxAttachmentsBytes);
  };

  const resetForm = () => {
    reset();
    setImages([]);
  };

  const submit = async (values: { body: string }) => {
    const uploadImages = await uploadAllImages(images);

    const formData = {
      body: values.body,
      ...(!!taggedUsers?.length && {
        bodyAttributes: taggedUsers,
        taggedUserIds: taggedUsers.map(attribute => attribute.type.user.id),
      }),
      attachments: uploadImages.filter(attachment => attachment),
    };
    postMutation.mutate(formData);
    resetForm();
  };

  const handleAddImage = (image: FormFileType) => setImages([...images, image]);
  const handleDeleteImage = (attachment: Attachment, index: number) => {
    const newList = [...images];
    newList.splice(index, 1);

    setImages(newList);
  };

  const handleChangeTaggedUsers = (updater: Updater<TaggedUser[]>) => {
    if (typeof updater === 'function') {
      setTaggedUsers(prev => {
        const result = updater(prev);
        return result !== undefined ? result : prev;
      });
    } else if (updater !== undefined) {
      setTaggedUsers(updater);
    }
  };

  const body = watch('body');
  const hasImages = images?.length > 0;
  const hasAttachments = images?.length > 0;
  const imagesAttach = useMemo(() => images.map(getAttachment), [images]);

  const handleAddEmoji = (emoji: string) => setValue('body', body + emoji);

  const handleKeyDown = (event: KeyboardEvent) => {
    if (event.key === 'Enter' && !event.shiftKey) {
      event.preventDefault();
      if ((!body && !hasImages) || isSubmitting) return;
      handleSubmit(submit)();
    }
  };

  return (
    <Stack>
      <Stack
        sx={{
          flexDirection: 'row',
          gap: 1,
          pt: 2,
        }}
      >
        <HuAvatar
          src={loggedUser?.profilePicture || ''}
          text={getInitials(getFullName(loggedUser))}
        />
        <FormProvider {...form}>
          <form
            noValidate
            onSubmit={handleSubmit(submit)}
            style={{ width: '90%' }}
          >
            <Stack
              sx={{
                borderRadius: '20px',
                flex: 'auto',
                width: '100%',
              }}
            >
              <FormTextFieldTagUsers
                name="body"
                variant="outlined"
                placeholder={t('ADD_COMMENT')}
                isSubmitting={isSubmitting}
                taggedUsers={taggedUsers}
                onChangeTaggedUsers={handleChangeTaggedUsers}
                onKeyDown={handleKeyDown}
                sx={{
                  '& .MuiInputBase-root': {
                    borderRadius: 2,
                    background: theme.palette.new.background.layout.default,
                    minHeight: '100px',
                    flexDirection: 'column',
                    justifyContent: 'space-between',
                  },
                  '& .MuiOutlinedInput-notchedOutline, & .MuiOutlinedInput-notchedOutline:hover':
                    {
                      border: 'none',
                    },
                }}
                InputProps={{
                  id: COMMENT_ADD_INPUT_ID,
                  sx: {
                    '& textarea': {
                      minWidth: '160px',
                    },
                  },
                  disableUnderline: hasImages,
                  endAdornment: (
                    <InputAdornment
                      position="end"
                      sx={{
                        height: 'auto',
                        width: '100%',
                        justifyContent: 'space-between',
                      }}
                    >
                      <Stack
                        sx={{
                          flexDirection: 'row',
                          alignItems: 'center',
                        }}
                      >
                        <ReactionAdd
                          onAdd={handleAddEmoji}
                          bgColor="transparent"
                          iconColor={theme.palette.new.text.neutral.brand}
                          tooltipProps={{
                            slotProps: {
                              popper: {
                                container: containerElement,
                              },
                            },
                          }}
                        />
                        {canAddImages && (
                          <AttachmentsAdd
                            onAddImage={handleAddImage}
                            gifDisabled={hasAttachments}
                            iconCustomPhoto={<IconPaperclip />}
                            size="medium"
                            disabled={
                              isSubmitting || !isValidAttachments() || hasImages
                            }
                            iconColor={theme.palette.new.text.neutral.brand}
                          />
                        )}
                      </Stack>
                      <Tooltip title={t('SEND')}>
                        <IconButton
                          disabled={(!body && !hasImages) || isSubmitting}
                          type="submit"
                        >
                          <IconSend />
                        </IconButton>
                      </Tooltip>
                    </InputAdornment>
                  ),
                }}
              />
              {hasAttachments && (
                <AttachmentsList
                  images={imagesAttach}
                  onDelete={handleDeleteImage}
                  disabled={isSubmitting}
                  isComment
                />
              )}
            </Stack>
            {maxAttachmentsBytes && hasImages && (
              <Stack
                sx={{
                  flexDirection: 'row',
                  alignItems: 'center',
                  justifyContent: 'space-between',
                  mt: 1,
                }}
              >
                <AttachmentsSize
                  sx={{ pr: 1 }}
                  images={imagesAttach}
                  maxBytes={maxAttachmentsBytes}
                  addPost
                />
              </Stack>
            )}
          </form>
        </FormProvider>
      </Stack>
    </Stack>
  );
};

export default AddComment;
