import { type ReactNode, Suspense, useEffect, useMemo } from 'react';
import { FormProvider } from 'react-hook-form';
import { useQuery } from 'react-query';
import { useNavigate } from 'react-router-dom';

import { useDrawerV2 } from '@material-hu/hooks/useDrawerV2';
import ImageIcon from '@material-hu/icons/material/Image';
import { IconAccessPoint } from '@material-hu/icons/tabler';
import Box from '@material-hu/mui/Box';
import CircularProgress from '@material-hu/mui/CircularProgress';
import Stack from '@material-hu/mui/Stack';
import { type SxProps } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';

import Alert from '@material-hu/components/design-system/Alert';
import Button from '@material-hu/components/design-system/Buttons/Button';
import Skeleton from '@material-hu/components/design-system/Skeleton';

import { logEvent } from 'src/config/amplitude';
import { useAuth } from 'src/contexts/JWTContext';
import { usePosts } from 'src/contexts/PostContext';
import useCommunityFeature from 'src/hooks/useCommunityFeature';
import useFeatureFlag from 'src/hooks/useFeatureFlag';
import usePermissions from 'src/hooks/usePermissions';
import usePosting, { type GenericUsePostingProps } from 'src/hooks/usePosting';
import PreviewLinkCard from 'src/pages/dashboard/feed/components/PreviewLinkCard';
import {
  PollAdd,
  PollReadOnly,
  usePollDrawer,
} from 'src/pages/dashboard/feed/components/poll';
import { feedKeys } from 'src/pages/dashboard/feed/queries';
import { getAmountUsersReachSegmentation } from 'src/services/users';
import { EventName } from 'src/types/amplitude';
import { CommunityFeature } from 'src/types/communityFeatures';
import { FeatureFlags } from 'src/types/featureFlags';
import { type PollState } from 'src/types/feed';
import { type GroupPost } from 'src/types/groups';
import { type Post } from 'src/types/posts';
import { StreamDestination } from 'src/types/stream';
import { bytesFrom } from 'src/utils/bytes';
import { buildPostDraftKey, readComposerDraft } from 'src/utils/composerDrafts';
import {
  getEditionPublishText,
  getNonTextReadOnlySx,
} from 'src/utils/editionApproval';
import { getSegmentationArray } from 'src/utils/feed';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';
import { lazyRetry } from 'src/utils/lazyRetry';
import { UserPermissions } from 'src/utils/permissions';

import {
  AttachmentsAdd,
  AttachmentsList,
  AttachmentsSize,
} from 'src/components/attachment';
import ErrorDialog from 'src/components/dialogs/ErrorDialog';
import LoadingButton from 'src/components/LoadingButton';
import LoggedUserAvatar from 'src/components/LoggedUserAvatar';
import Segmentate from 'src/components/segmentations/Segmentate';

import { feedRoutes } from '../routes';

import CancelPostEditionAlert from './CancelPostEditionAlert';
import getScheduleDrawerConfig from './schedule/components/ScheduleDrawerContent';
import SchedulePostButton from './schedule/components/SchedulePostButton';
import { useScheduleDrawerState } from './schedule/components/useScheduleDrawerState';

const RichTextEditor = lazyRetry(() => import('src/components/RichTextEditor'));

export type PostAddFormProps<T extends Post | GroupPost = Post> =
  GenericUsePostingProps<T> & {
    isRequestingEditionApproval?: boolean;
    /** Slot rendered after the rich-text editor and before the attachments list (used by share-post). */
    embeddedSlot?: ReactNode;
    /** Hide the "Schedule" button (used by share-post flow). */
    hideSchedule?: boolean;
    /** Hide the "Live Stream" button (used by share-post flow). */
    hideLiveStream?: boolean;
    /** Hide the segmentation selector (used by share-post flow). */
    hideSegmentate?: boolean;
    /** Override the submit button label. */
    submitButtonLabel?: string;
    /** Render an extra secondary button next to submit (used as "Back" by share-post). */
    secondaryButton?: {
      label: string;
      onClick: () => void;
      disabled?: boolean;
    };
    /** Override the sx of the outer actions row container (used by share-post to render it as a page footer). */
    actionsContainerSx?: SxProps;
    /** Adds an id attribute to the <form> element so an external submit button can use form={formId}. */
    formId?: string;
    /** When true, hides the entire actions row (toolbar + submit buttons). Used with formId to submit from outside. */
    hideActions?: boolean;
    /** When true, hides only the submit buttons row but keeps the attachment toolbar visible. */
    hideSubmitRow?: boolean;
    /** Called whenever the submitting state changes. Used by share-post to sync the external submit button's loading state. */
    onSubmittingChange?: (isSubmitting: boolean) => void;
    /** Override the destination label shown below the user's name (used by share-post to show feed/group destination). */
    destinationLabel?: string;
  };

const {
  CREATE_LIVESTREAM,
  VIEW_LIVESTREAM,
  REQUEST_FEED_POST_APPROVAL,
  CAN_APPROVE_FEED_POSTS,
} = UserPermissions;

const PostAddForm = <T extends Post | GroupPost = Post>(
  props: PostAddFormProps<T>,
): JSX.Element => {
  const {
    isEdit = false,
    defaultBodyHtml = '',
    isRequestingEditionApproval: isRequestingEditionApprovalOverride,
    embeddedSlot,
    hideSchedule = false,
    hideLiveStream = false,
    hideSegmentate = false,
    submitButtonLabel,
    secondaryButton,
    actionsContainerSx,
    formId,
    hideActions = false,
    hideSubmitRow = false,
    onSubmittingChange,
    destinationLabel,
    ...usePostingProps
  } = props;

  const { t } = useTranslation();
  const { hasAll: postNeedApproval } = usePermissions([
    REQUEST_FEED_POST_APPROVAL,
  ]);
  const { hasAll: canCreateLiveStream } = usePermissions([
    CREATE_LIVESTREAM,
    VIEW_LIVESTREAM,
    ...(postNeedApproval ? [CAN_APPROVE_FEED_POSTS] : []),
  ]);
  const { hasAll: hasSendPushPermission } = usePermissions([
    UserPermissions.SEND_PUSH_NOTIFICATION,
  ]);

  const isPublicPostNotificationsMuted = useFeatureFlag(
    FeatureFlags.PUBLIC_POST_NOTIFICATIONS_MUTED,
  );

  const navigate = useNavigate();

  const { user, instance: authInstance } = useAuth();
  const draftKey =
    user && authInstance
      ? buildPostDraftKey({
          scope: 'feed',
          instanceId: authInstance.id,
          userId: user.id,
        })
      : null;
  const initialComposerContent = useMemo(() => {
    if (isEdit || !draftKey) {
      return defaultBodyHtml;
    }

    return readComposerDraft(draftKey) || defaultBodyHtml;
  }, [isEdit, draftKey, defaultBodyHtml]);

  const {
    instance,
    openError,
    closeErrorDialog,
    form,
    handleSubmit,
    submit,
    segmentationItems,
    handleSegmentateChange,
    canSegmentate,
    imagesAttach,
    filesAttach,
    videosAttach,
    audiosAttach,
    isSubmitting,
    showPreviewLink,
    urls,
    metadata,
    isLoadingPreviewLink,
    handleRemovePreviewLink,
    hasAttachments,
    gif,
    handleDelete,
    handleRemoveGif,
    canAddPoll,
    withPoll,
    setWithPoll,
    handlePollUpdate,
    pollOptionsForEdit,
    pollState,
    canRemovePoll,
    handleAddFiles,
    handleAddGif,
    handleAddMultimedia,
    attachmentsDisabled,
    images,
    videos,
    files,
    handleEditCancel,
    openCancelDialog,
    setOpenCancelDialog,
    handleOnDiscard,
    isValidPost,
    disabledSubmitButton,
    handleCheckNotificationAndSubmit,
    handleSchedulePost,
    handleChangePositionMultimedia,
    handlePaste,
    pollVotersVisible,
    handlePollVotersVisibilityChange,
    pollDeadlineEnabled,
    pollEndsAt,
    handlePollDeadlineChange,
    shouldClearPollWhenCancelling,
    notificationAlertModal,
  } = usePosting({
    ...usePostingProps,
    isEdit,
    defaultBodyHtml,
    draftKey,
  });

  const canSendPush =
    hasSendPushPermission &&
    !(isPublicPostNotificationsMuted && segmentationItems.size === 0);

  const { isPosting } = usePosts();

  const canViewGroupPostsInFeed = useCommunityFeature(
    CommunityFeature.VIEW_GROUP_POSTS_IN_FEED,
  );

  const { data: amountOfUsersReach } = useQuery(
    feedKeys.segmentate.usersCount(
      getSegmentationArray(segmentationItems) as string,
      true,
    ),
    () =>
      getAmountUsersReachSegmentation(
        {
          instanceId: instance!.id,
          segmentationItemIds: getSegmentationArray(
            segmentationItems,
          ) as string, // Will always return a string because segmentationItems is a Map<number, SegmentationMapValues[]> (see enabled condition)
          includeLoggedUser: true,
        },
        true,
      ),
    {
      enabled: !!segmentationItems && !!instance?.id,
      keepPreviousData: true,
    },
  );

  const onSchedulePost = (date: string, sendNotification: boolean) => {
    handleSchedulePost(new Date(date), sendNotification);
  };

  const goToLiveStream = () => {
    navigate(feedRoutes.liveStream());
    logEvent(EventName.LIVESTREAM_SETUP_STARTED, {
      userId: user?.id ?? '',
      destination: StreamDestination.FEED,
      destinationID: '',
    });
  };

  const showLiveStreamButton = instance?.allowLiveStream || canCreateLiveStream;
  const isPostFeedSubmitting = isSubmitting || isPosting;
  const isButtonFeedDisabled = disabledSubmitButton || isPosting;

  useEffect(() => {
    onSubmittingChange?.(isPostFeedSubmitting);
  }, [isPostFeedSubmitting, onSubmittingChange]);
  const isScheduleDisabled = !isValidPost() || isPostFeedSubmitting;
  const isRequestingEditionApproval =
    isRequestingEditionApprovalOverride ?? false;
  const nonTextReadOnlySx = getNonTextReadOnlySx(isRequestingEditionApproval);

  const pollDrawerState = useMemo((): PollState => {
    if (!isRequestingEditionApproval || pollState.form.disabled) {
      return pollState;
    }
    return {
      form: { disabled: true, message: '' },
      cancel: { disabled: true, message: '' },
    };
  }, [isRequestingEditionApproval, pollState]);
  const showSegmentate =
    !hideSegmentate &&
    canSegmentate &&
    !canViewGroupPostsInFeed &&
    !isRequestingEditionApproval;

  const getPublishText = () =>
    submitButtonLabel ??
    getEditionPublishText({
      t,
      isSubmitting: isPostFeedSubmitting,
      isEdit,
      isRequestingEditionApproval,
    });

  const scheduleDrawerState = useScheduleDrawerState({
    onSchedulePost,
    canSendPush,
  });
  const { drawer: scheduleDrawer, showDrawer: showScheduleDrawer } =
    useDrawerV2(({ closeDrawer }) =>
      getScheduleDrawerConfig(scheduleDrawerState, closeDrawer),
    );

  const { drawer: pollCreateDrawer, showDrawer: showPollDrawer } =
    usePollDrawer({
      withPoll,
      canAddPoll,
      isSubmitting: isPostFeedSubmitting,
      pollState: pollDrawerState,
      pollOptionsForEdit,
      pollVotersVisible,
      isEdit,
      onPollUpdate: handlePollUpdate,
      onPollVotersVisibilityChange: handlePollVotersVisibilityChange,
      pollDeadlineEnabled,
      pollEndsAt,
      onPollDeadlineChange: handlePollDeadlineChange,
      setWithPoll,
      shouldClearPollWhenCancelling,
    });

  return (
    <>
      <ErrorDialog
        open={openError}
        onAccept={closeErrorDialog}
        message={t('post:error_max_attachments_size')}
      />
      <FormProvider {...form}>
        <form
          id={formId}
          noValidate
          onSubmit={handleSubmit(submit)}
        >
          <Box>
            <Box
              sx={{
                display: { xs: 'block', sm: 'flex' },
                justifyContent: 'space-between',
                alignItems: 'center',
              }}
            >
              <LoggedUserAvatar
                selectedItems={segmentationItems}
                onChange={handleSegmentateChange}
                hasItemsSegmetated={segmentationItems.size !== 0}
                showSegmentate={showSegmentate}
                labelOverride={destinationLabel}
              />
              <Box
                sx={{
                  display: 'flex',
                  flexDirection: { xs: 'row', sm: 'column' },
                  justifyContent: 'space-between',
                  alignSelf: 'flex-start',
                  pb: { xs: 1, sm: 0 },
                }}
              >
                <Segmentate
                  selectedItems={segmentationItems}
                  onChange={handleSegmentateChange}
                  amountOfUsersReach={amountOfUsersReach ?? 0}
                  showSegmentate={showSegmentate}
                />
                <Box
                  sx={{
                    display: 'flex',
                    justifyContent: 'flex-end',
                    width: { sm: '100%' },
                    pr: 0,
                  }}
                >
                  <AttachmentsSize
                    sx={{ ml: 1 }}
                    images={imagesAttach}
                    files={filesAttach}
                    videos={videosAttach}
                    audios={audiosAttach}
                    maxBytes={bytesFrom(instance?.maxPostSizeInMB ?? 0, 'MB')}
                    addPost
                  />
                </Box>
              </Box>
            </Box>
            <Suspense
              fallback={
                <Skeleton
                  height={60}
                  width="100%"
                />
              }
            >
              <RichTextEditor
                name="bodyHtml"
                content={initialComposerContent}
                isEdit={isEdit}
                handlePaste={handlePaste}
                disabled={isPostFeedSubmitting}
              />
            </Suspense>
            {showPreviewLink && (
              <PreviewLinkCard
                linkPreviews={{ [urls[0]]: metadata?.data }}
                isLoading={isLoadingPreviewLink}
                onRemove={handleRemovePreviewLink}
              />
            )}
            {hasAttachments && (
              <Box sx={nonTextReadOnlySx}>
                <AttachmentsList
                  sx={{ my: 0.5 }}
                  gif={gif}
                  images={imagesAttach}
                  files={filesAttach}
                  videos={videosAttach}
                  audios={audiosAttach}
                  onDelete={
                    isRequestingEditionApproval ? undefined : handleDelete
                  }
                  onRemoveGif={
                    isRequestingEditionApproval ? undefined : handleRemoveGif
                  }
                  disabled={isPostFeedSubmitting || isRequestingEditionApproval}
                  isPost
                  handleChangePositionMultimedia={
                    handleChangePositionMultimedia
                  }
                />
              </Box>
            )}
            {embeddedSlot && <Box sx={{ mt: 1.5, mb: 1 }}>{embeddedSlot}</Box>}

            {/* Show read-only poll when poll options exist */}
            {withPoll &&
              pollOptionsForEdit.length > 0 &&
              pollOptionsForEdit.some(option => option.trim()) && (
                <PollReadOnly
                  options={pollOptionsForEdit.filter(option => option.trim())}
                  onEdit={
                    isRequestingEditionApproval
                      ? undefined
                      : () => showPollDrawer({})
                  }
                  onRemove={
                    canRemovePoll && !isRequestingEditionApproval
                      ? () => {
                          handlePollUpdate([]);
                          setWithPoll(false);
                        }
                      : undefined
                  }
                />
              )}

            {isRequestingEditionApproval && (
              <Alert
                severity="info"
                title={t('post:send_for_review')}
                description={t('post:edited_version_pending_approval')}
                sx={{ mt: 2, mb: 1.5 }}
              />
            )}

            {!hideActions && (
              <Stack
                sx={{
                  flexDirection: 'row',
                  justifyContent: 'space-between',
                  alignItems: 'center',
                  width: '100%',
                  pt: { xs: 1, sm: 1.5 },
                  ...actionsContainerSx,
                }}
              >
                <Stack
                  sx={{
                    flexDirection: 'row',
                    justifyContent: 'start',
                    alignItems: 'center',
                    flexWrap: 'wrap',
                    color: theme => theme.palette.new.text.neutral.default,
                  }}
                >
                  {!isRequestingEditionApproval && (
                    <AttachmentsAdd
                      onAddMultipleFiles={handleAddFiles}
                      onAddGif={handleAddGif}
                      onAddMultimedia={handleAddMultimedia}
                      gifDisabled={hasAttachments || withPoll}
                      disabled={attachmentsDisabled}
                      multimediaSize={images.length + videos.length}
                      filesSize={files.length}
                      iconCustomPhoto={<ImageIcon />}
                      checkMax={false}
                      direction="bottom"
                    />
                  )}
                  {canAddPoll && !isRequestingEditionApproval && (
                    <PollAdd
                      onAdd={() => setWithPoll(true)}
                      disabled={withPoll || !!gif || isPostFeedSubmitting}
                      sx={{ color: 'primary.main' }}
                    />
                  )}
                </Stack>
                {!hideSubmitRow && (
                  <Stack
                    sx={{
                      flexDirection: {
                        xs: isRequestingEditionApproval ? 'column' : 'row',
                        sm: 'row',
                      },
                      justifyContent: 'flex-end',
                      alignItems: {
                        xs: isRequestingEditionApproval ? 'stretch' : 'center',
                        sm: 'center',
                      },
                      gap: isRequestingEditionApproval ? 1 : 0,
                    }}
                  >
                    {isEdit && (
                      <Button
                        disabled={isPostFeedSubmitting}
                        onClick={handleEditCancel}
                        variant="outlined"
                        type="button"
                        sx={{
                          py: 1.5,
                          height: '100%',
                          width: {
                            xs: isRequestingEditionApproval ? '100%' : 'auto',
                            sm: 'auto',
                          },
                        }}
                      >
                        <Typography
                          variant="globalS"
                          fontWeight={'fontWeightSemiBold'}
                          color={theme => theme.palette.new.text.neutral.brand}
                        >
                          {t('general:cancel')}
                        </Typography>
                      </Button>
                    )}
                    <CancelPostEditionAlert
                      open={openCancelDialog}
                      onClose={() => setOpenCancelDialog(false)}
                      onDiscard={handleOnDiscard}
                    />
                    {!isEdit && (
                      <Stack
                        sx={{
                          gap: 1,
                          flexDirection: 'row',
                          alignItems: 'stretch',
                          alignSelf: 'stretch',
                        }}
                      >
                        {showLiveStreamButton && !hideLiveStream && (
                          <Button
                            startIcon={<IconAccessPoint />}
                            variant="secondary"
                            sx={{
                              py: 1.5,
                              height: '100%',
                            }}
                            onClick={goToLiveStream}
                          >
                            <Typography
                              variant="globalS"
                              fontWeight="fontWeightSemiBold"
                              color={theme =>
                                theme.palette.new.text.neutral.brand
                              }
                            >
                              {t('post:transmit')}
                            </Typography>
                          </Button>
                        )}
                        {!hideSchedule && (
                          <SchedulePostButton
                            disabled={isScheduleDisabled}
                            onClick={() => showScheduleDrawer({})}
                          />
                        )}
                      </Stack>
                    )}
                    {secondaryButton && (
                      <Button
                        variant="outlined"
                        type="button"
                        disabled={
                          secondaryButton.disabled || isPostFeedSubmitting
                        }
                        onClick={secondaryButton.onClick}
                        sx={{ py: 1.5, height: '100%', mr: 1 }}
                      >
                        <Typography
                          variant="globalS"
                          fontWeight="fontWeightSemiBold"
                          color={theme => theme.palette.new.text.neutral.brand}
                        >
                          {secondaryButton.label}
                        </Typography>
                      </Button>
                    )}
                    <LoadingButton
                      variant="contained"
                      onClick={() =>
                        handleCheckNotificationAndSubmit(canSendPush)
                      }
                      loadingIndicator={
                        <CircularProgress
                          size={16}
                          color="inherit"
                          sx={{ my: 0.5 }}
                        />
                      }
                      loading={isPostFeedSubmitting}
                      disabled={isButtonFeedDisabled}
                      sx={{
                        ml: isRequestingEditionApproval ? { xs: 0, sm: 1 } : 1,
                        px: 2,
                        py: 1.5,
                        height: '100%',
                        width: {
                          xs: isRequestingEditionApproval ? '100%' : 'auto',
                          sm: 'auto',
                        },
                        '&.Mui-disabled': {
                          backgroundColor: theme =>
                            isPostFeedSubmitting
                              ? theme.palette.new.action.button.background
                                  .primary.default
                              : undefined,
                          color: isPostFeedSubmitting
                            ? theme => theme.palette.new.text.neutral.disabled
                            : undefined,
                        },
                      }}
                    >
                      <Typography
                        variant="globalS"
                        fontWeight={'fontWeightSemiBold'}
                        color={
                          !isButtonFeedDisabled
                            ? theme => theme.palette.new.text.neutral.inverted
                            : undefined
                        }
                      >
                        {getPublishText()}
                      </Typography>
                    </LoadingButton>
                  </Stack>
                )}
              </Stack>
            )}
          </Box>
        </form>
        {pollCreateDrawer}
      </FormProvider>
      {scheduleDrawer}
      {notificationAlertModal}
    </>
  );
};

export default PostAddForm;
