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

import { type AxiosResponse } from 'axios';
import { isEqual } from 'lodash-es';
import ImageIcon from '@material-hu/icons/material/Image';
import Box from '@material-hu/mui/Box';
import CircularProgress from '@material-hu/mui/CircularProgress';
import InputAdornment from '@material-hu/mui/InputAdornment';
import Stack from '@material-hu/mui/Stack';
import Tooltip from '@material-hu/mui/Tooltip';
import Typography from '@material-hu/mui/Typography';

import Button from '@material-hu/components/design-system/Buttons/Button';
import HuDrawer from '@material-hu/components/design-system/Drawer';
import HuFormInputMoney from '@material-hu/components/design-system/Inputs/Money/form';

import { logEvent } from 'src/config/logging';
import { useAuth } from 'src/contexts/JWTContext';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import { FormTextFieldTagUsers } from 'src/pages/dashboard/marketplace/components/inputs';
import MarketplaceDiscardChangesDialog from 'src/pages/dashboard/marketplace/components/MarketplaceDiscardChangesDialog';
import { uploadAllAttachments } from 'src/services/attachments';
import { EventName } from 'src/types/amplitude';
import {
  FileTypes,
  type FormFile as FormFileType,
} from 'src/types/attachments';
import {
  type MarketplacePost,
  type MarketplacePostData,
} from 'src/types/marketplace';
import { type Updater } from 'src/types/queries';
import { type TaggedUser } from 'src/types/user';
import {
  deleteFileAndReorderAttchaments,
  getCorrectPositionOfFile,
  getFileToPaste,
  hasFileToPaste,
  isValidFilesSize,
} from 'src/utils/attachments';
import { bytesFrom } from 'src/utils/bytes';
import { getAttachment } from 'src/utils/files';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';
import { getCurrentLocale } from 'src/utils/locale';
import { functionalUpdate } from 'src/utils/queries';
import { getFullName } from 'src/utils/userUtils';

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

type MarketplaceFormValues = {
  price: { amount: number; currencyCode: string | null };
  body: string;
  bodyAttributes: TaggedUser[];
  images: FormFileType[];
  videos: FormFileType[];
  files: FormFileType[];
};

export type MarketplacePostAddDrawerProps = {
  isEdit?: boolean;
  defaultBody?: string;
  defaultBodyAttributes?: TaggedUser[];
  defaultPrice?: {
    amount: number;
    currencyCode: string | null;
  };
  defaultImages?: FormFileType[];
  defaultVideos?: FormFileType[];
  defaultFiles?: FormFileType[];
  onCancel?: () => void;
  request: (
    body: MarketplacePostData,
  ) => Promise<AxiosResponse<MarketplacePost>>;
  onSuccess?: (data: MarketplacePost) => void;
  onError?: (error: any) => void;
  open: boolean;
};

const MAX_SIZE_ATTACHMENTS = 100;
const MAX_SAFE_INPUT_LENGTH = 11;

export const MarketplacePostAddDrawer: FC<
  MarketplacePostAddDrawerProps
> = props => {
  const {
    isEdit = false,
    defaultBody = '',
    defaultBodyAttributes = [],
    defaultPrice = {
      currencyCode: null,
      amount: 0,
    },
    defaultImages = [],
    defaultVideos = [],
    defaultFiles = [],
    onCancel = () => null,
    request,
    onSuccess = () => null,
    onError = () => null,
    open = false,
  } = props;

  const [lastCursor, setLastCursor] = useState<number | null>(null);
  const [openDiscardChangesDialog, setOpenDiscardChangesDialog] =
    useState<boolean>(false);
  const { t } = useTranslation(['marketplace', 'general']);
  const { user, instance } = useAuth();
  const HuGoThemeProvider = useHuGoTheme();

  const form = useForm({
    defaultValues: {
      price: {
        amount: defaultPrice.amount,
        currencyCode:
          defaultPrice.currencyCode ?? instance?.defaultCurrencyCode ?? null,
      },
      body: defaultBody,
      bodyAttributes: defaultBodyAttributes,
      images: defaultImages,
      videos: defaultVideos,
      files: defaultFiles,
    },
    values: {
      price: {
        amount: defaultPrice.amount,
        currencyCode:
          defaultPrice.currencyCode ?? instance?.defaultCurrencyCode ?? null,
      },
      body: defaultBody,
      bodyAttributes: defaultBodyAttributes,
      images: defaultImages,
      videos: defaultVideos,
      files: defaultFiles,
    },
  });

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

  const { body, price, bodyAttributes, images, videos, files } = watch();

  // Ensure form is properly initialized before rendering
  const isFormInitialized =
    price && price.amount !== undefined && price.currencyCode !== undefined;

  const postMutation = useMutation(request, {
    onSuccess: response => {
      if (bodyAttributes?.length) {
        bodyAttributes.forEach(elem => {
          logEvent(EventName.POST_MARKETPLACE_MENTION, {
            postId: response.data?.id,
            userId: elem.type?.user.id,
          });
        });
      }

      onSuccess(response.data);

      reset();
    },
    onError,
  });

  useEffect(() => {
    if (body !== '') {
      const input = document.getElementById(
        'marketplacePostAddInput',
      ) as HTMLInputElement;
      setFocus('body');
      if (lastCursor) {
        input.setSelectionRange(lastCursor, lastCursor);
        setLastCursor(null);
      }
    }
  }, [body]);

  const submit = async (values: MarketplaceFormValues) => {
    try {
      const [uploadFiles, uploadImages, uploadVideos] =
        await uploadAllAttachments(values.files, values.images, values.videos);

      const taggedUserIds = values.bodyAttributes.map(
        (attribute: TaggedUser) => attribute.type.user.id,
      );

      const formData = {
        body: values.body,
        price: Number(price.amount),
        currencyCode: price.currencyCode ?? null,
        bodyAttributes: values.bodyAttributes,
        attachments: [...uploadImages, ...uploadFiles, ...uploadVideos].filter(
          attachment => attachment,
        ),
        taggedUserIds,
      };

      postMutation.mutate(formData);
    } catch (error) {
      onError(error);
    }
  };

  const handleAddImage = (imageParam: Omit<FormFileType, 'position'>) => {
    const image = [...images];
    const video = [...videos];

    const position = getCorrectPositionOfFile(image, video);
    image.push({ position, ...imageParam });
    setValue('images', [...image]);
  };

  const handleAddMultipleAttachment = (newFiles: any[]) => {
    const image = [...images];
    const video = [...videos];

    newFiles.forEach((elem, index) => {
      const position = getCorrectPositionOfFile(image, video, index);
      if (elem.type === FileTypes.IMAGE) {
        image.push({ position, ...elem });
      } else if (elem.type === FileTypes.VIDEO) {
        video.push({ position, ...elem });
      }
    });
    setValue('images', [...image]);
    setValue('videos', [...video]);
  };

  const handleDeleteAttachment = (attachment: any, index: number) => {
    if (attachment.type === FileTypes.FILE) {
      const newFiles = [...files];
      newFiles.splice(index, 1);
      setValue('files', newFiles);
    } else {
      const { newImages, newVideos } = deleteFileAndReorderAttchaments(
        images,
        videos,
        attachment,
      );
      setValue('images', newImages);
      setValue('videos', newVideos);
    }
  };

  const handleAddAttachment = (file: FormFileType) => {
    setValue('files', [...files, file]);
  };

  const handleChangeTaggedUsers = (updater: Updater<TaggedUser[]>) =>
    setValue(
      'bodyAttributes',
      functionalUpdate(updater, getValues('bodyAttributes')),
    );

  const handleAddEmoji = (emoji: string) => {
    const input = document.getElementById(
      'marketplacePostAddInput',
    ) as HTMLInputElement;
    const start = Math.min(input.selectionStart ?? 0, input.selectionEnd ?? 0);
    const end = Math.max(input.selectionStart ?? 0, input.selectionEnd ?? 0);

    const textStart = body.slice(0, start);
    const textEnd = body.slice(end);

    setValue('body', textStart + emoji + textEnd);
    setLastCursor(start + 1 + emoji.length);
  };

  const handlePaste = async (event: React.ClipboardEvent<HTMLInputElement>) => {
    if (!hasFileToPaste(event)) return;

    event.preventDefault();

    const newFile = await getFileToPaste(event);
    if (newFile) {
      handleAddImage(newFile);
    }
  };

  const handleDiscard = () => {
    if (hasDifference()) {
      setOpenDiscardChangesDialog(true);
      return;
    }

    onCancel();
    reset();
  };

  const handleDiscardAccept = () => {
    setOpenDiscardChangesDialog(false);
    onCancel();
    reset();
  };

  const handleDiscardCancel = () => {
    setOpenDiscardChangesDialog(false);
  };

  const isValidPost = (): boolean =>
    !!price?.amount && !!price?.currencyCode && body?.length > 0;

  const isValidAttachments = (): boolean => {
    const attachments: FormFileType[] = [
      ...(files?.length > 0 ? files : []),
      ...(videos?.length > 0 ? videos : []),
      ...(images?.length > 0 ? images : []),
    ];

    return isValidFilesSize(attachments);
  };

  const imagesAttach = useMemo(() => images.map(getAttachment), [images]);
  const videosAttach = useMemo(() => videos.map(getAttachment), [videos]);
  const filesAttach = useMemo(() => files.map(getAttachment), [files]);

  const hasDifference = () =>
    !isEqual(images, defaultImages) ||
    !isEqual(videos, defaultVideos) ||
    !isEqual(files, defaultFiles) ||
    !isEqual(bodyAttributes, defaultBodyAttributes) ||
    !isEqual(body, defaultBody) ||
    !isEqual(price, defaultPrice);

  const hasAttachments =
    imagesAttach?.length > 0 ||
    videosAttach?.length > 0 ||
    filesAttach?.length > 0;

  return (
    <HuGoThemeProvider>
      <FormProvider {...form}>
        <MarketplaceDiscardChangesDialog
          open={openDiscardChangesDialog}
          onCancel={handleDiscardCancel}
          onDiscard={handleDiscardAccept}
          cancelLabel={
            isEdit ? t('general:keep_editing') : t('marketplace:keep_creating')
          }
        />
        <HuDrawer
          title={t('marketplace:create_post_title')}
          component="form"
          onSubmit={handleSubmit(submit)}
          PaperProps={{
            sx: {
              color: theme => theme.palette.new.text.neutral.default,
            },
          }}
          open={open}
          onClose={handleDiscard}
          footer={
            <Box>
              <Tooltip
                title={
                  !isValidAttachments() &&
                  t('marketplace:error_max_attachments_size')
                }
              >
                <span>
                  <Button
                    type="submit"
                    disabled={
                      !isValidPost() ||
                      isSubmitting ||
                      (isEdit && !hasDifference()) ||
                      !isValidAttachments()
                    }
                    variant="contained"
                    fullWidth
                  >
                    {isSubmitting && (
                      <>
                        <CircularProgress
                          size={16}
                          color="inherit"
                          sx={{ mr: 1 }}
                        />
                        {isEdit
                          ? t('general:saving')
                          : t('marketplace:publishing')}
                      </>
                    )}
                    {!isSubmitting && (
                      <>
                        {isEdit ? t('general:save') : t('marketplace:publish')}
                      </>
                    )}
                  </Button>
                </span>
              </Tooltip>
            </Box>
          }
        >
          <Box
            sx={{
              p: 2,
              border: theme =>
                `1px solid ${theme.palette.new.border.neutral.default}`,
              borderRadius: theme => theme.shape.borderRadiusL,
            }}
          >
            <Stack spacing={2}>
              <Stack
                sx={{
                  flexDirection: 'row',
                  justifyContent: 'space-between',
                  alignItems: 'center',
                }}
              >
                <Stack
                  sx={{
                    flexDirection: 'row',
                    gap: 1,
                    alignItems: 'center',
                  }}
                >
                  {user && (
                    <ProfilePicture
                      id={user.id}
                      user={user}
                      size="small"
                    />
                  )}
                  {user && (
                    <Typography
                      variant="globalS"
                      color="neutralText"
                      fontWeight="fontWeightSemiBold"
                    >
                      {getFullName(user)}
                    </Typography>
                  )}
                </Stack>
                <AttachmentsSize
                  sx={{ m: 0 }}
                  images={imagesAttach}
                  files={filesAttach}
                  videos={videosAttach}
                  maxBytes={bytesFrom(MAX_SIZE_ATTACHMENTS, 'MB')}
                  addPost
                />
              </Stack>
              <div>
                {/* Only render HuFormInputMoney if price values are properly initialized */}
                {isFormInitialized && (
                  <HuFormInputMoney
                    name="price"
                    inputProps={{
                      placeholder: Intl.NumberFormat(
                        getCurrentLocale(user || ({} as any)).code,
                      ).format(40000),
                      label: t('marketplace:price'),
                      maxLength: MAX_SAFE_INPUT_LENGTH,
                      preventDecimals: true,
                    }}
                  />
                )}
              </div>
              <FormTextFieldTagUsers
                name="body"
                defaultBody={defaultBody}
                placeholder={t('marketplace:description_placeholder')}
                taggedUsers={bodyAttributes}
                isSubmitting={isSubmitting}
                onChangeTaggedUsers={handleChangeTaggedUsers}
                onPaste={handlePaste}
                stylesHighlighter={{ top: 24 }}
                InputProps={{
                  id: 'marketplacePostAddInput',
                  endAdornment: (
                    <InputAdornment
                      position="end"
                      sx={{ alignItems: 'center' }}
                    >
                      <ReactionAdd
                        onAdd={handleAddEmoji}
                        variant="icon"
                      />
                    </InputAdornment>
                  ),
                }}
              />
              {hasAttachments && (
                <AttachmentsList
                  images={imagesAttach}
                  files={filesAttach}
                  videos={videosAttach}
                  onDelete={handleDeleteAttachment}
                  disabled={isSubmitting}
                  isPost
                />
              )}
              <Box
                sx={{
                  display: { xs: 'block', sm: 'flex' },
                  justifyContent: 'space-between',
                  alignItems: 'center',
                  width: '100%',
                }}
              >
                <Stack
                  sx={{
                    flexDirection: 'row',
                    alignItems: 'center',
                    pt: { xs: 1, sm: 0 },
                  }}
                >
                  <AttachmentsAdd
                    onAddFile={handleAddAttachment}
                    onAddMultimedia={handleAddMultipleAttachment}
                    multimediaDisabled={
                      imagesAttach.length + videosAttach.length >= 10
                    }
                    fileDisabled={files.length >= 10}
                    disabled={isSubmitting || !isValidAttachments()}
                    multimediaSize={images.length + videos.length}
                    iconCustomPhoto={<ImageIcon fontSize="medium" />}
                  />
                </Stack>
              </Box>
            </Stack>
          </Box>
        </HuDrawer>
      </FormProvider>
    </HuGoThemeProvider>
  );
};

export default MarketplacePostAddDrawer;
