import Alert from '@material-hu/components/design-system/Alert';
import Button from '@material-hu/components/design-system/Buttons/Button';
import CardContainer from '@material-hu/components/design-system/CardContainer';
import Dialog from '@material-hu/components/design-system/Dialog';
import Dropdown from '@material-hu/components/design-system/Dropdown';
import Spinner from '@material-hu/components/design-system/ProgressIndicators/Spinner';
import useSnackbar from '@material-hu/components/design-system/Snackbar';
import StateCard from '@material-hu/components/design-system/StateCard';
import Tabs from '@material-hu/components/design-system/Tabs';
import { useModal } from '@material-hu/hooks/useModal';
import { type useServerPagination } from '@material-hu/hooks/useServerPagination';
import Box from '@material-hu/mui/Box';
import Checkbox from '@material-hu/mui/Checkbox';
import MenuItem from '@material-hu/mui/MenuItem';
import Stack from '@material-hu/mui/Stack';
import { type SxProps } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';
import { type AxiosResponse } from 'axios';
import { type FC, useCallback, useState } from 'react';
import { type UseQueryResult, useMutation } from 'react-query';

import useHuGoTheme from 'src/hooks/useHuGoTheme';
import {
  type FeedPendingApprovalPostList,
  type FeedPendingPost,
  OrderBy,
} from 'src/types/feed';
import {
  ApprovalStatus,
  type GroupPendingApprovalPostList,
  type GroupPendingPost,
  PendingPostReviewTypes,
} from 'src/types/groups';
import { PostRequestActionType } from 'src/types/posts';
import { useLokaliseTranslation } from 'src/utils/i18n';

import PendingPostCard from './PendingPostCard';
import { PENDING_REQUEST_TABS } from './pendingRequestTabs';

const PENDING_POSTS_APPROVAL_WIDTH = 688;

type PendingPostReviewModalProps = {
  type: PendingPostReviewTypes;
  onAction: () => void;
  onClose: () => void;
};
type Props = {
  pendingPostsQuery: UseQueryResult<
    GroupPendingApprovalPostList | FeedPendingApprovalPostList,
    unknown
  >;
  reviewPostsService: ({
    approvalStatus,
    postIds,
  }: {
    approvalStatus: ApprovalStatus;
    postIds: number[];
  }) => Promise<AxiosResponse<unknown, unknown>>;
  onReviewSuccess: (
    variables: { approvalStatus: ApprovalStatus; postIds: number[] },
    pendingPosts: GroupPendingPost[] | FeedPendingPost[],
  ) => void;
  selectedActionType: PostRequestActionType;
  onActionTypeChange: (actionType: PostRequestActionType) => void;
  serverPagination: ReturnType<typeof useServerPagination>;
  sx?: SxProps;
};

const PendingPostsApproval: FC<Props> = props => {
  const {
    pendingPostsQuery,
    reviewPostsService,
    onReviewSuccess,
    selectedActionType,
    onActionTypeChange,
    serverPagination,
    sx,
  } = props;
  const [selected, setSelected] = useState<number[]>([]);
  const [bulkSelectionMode, setBulkSelectionMode] = useState(false);
  const { enqueueSnackbar } = useSnackbar();
  const [dropdownOpen, setDropdownOpen] = useState(false);

  const handleDropdownToggle = useCallback(
    () => setDropdownOpen(prev => !prev),
    [],
  );
  const handleDropdownClose = useCallback(() => setDropdownOpen(false), []);

  const toggleBulkSelectionMode = () =>
    setBulkSelectionMode(_bulkSelectionMode => {
      if (!_bulkSelectionMode === false) {
        setSelected([]);
      }
      return !_bulkSelectionMode;
    });

  const { t } = useLokaliseTranslation('group');

  const orderByOptions = [
    { label: t(`group:${OrderBy.ASC.toLowerCase()}`), value: OrderBy.ASC },
    { label: t(`group:${OrderBy.DESC.toLowerCase()}`), value: OrderBy.DESC },
  ];

  const { paginationController, order, setOrder, setPage } = serverPagination;

  const { data, isLoading } = pendingPostsQuery;
  const { mutate: reviewPostsMutation } = useMutation(reviewPostsService, {
    onSuccess: (_data, variables) => {
      let pendingPostReviewType: PendingPostReviewTypes;
      if (variables.approvalStatus === ApprovalStatus.APPROVED) {
        pendingPostReviewType =
          variables.postIds.length === 1
            ? PendingPostReviewTypes.APPROVE_ONE
            : PendingPostReviewTypes.APPROVE_SELECTED;
      } else {
        pendingPostReviewType =
          variables.postIds.length === 1
            ? PendingPostReviewTypes.REJECT_ONE
            : PendingPostReviewTypes.REJECT_SELECTED;
      }
      enqueueSnackbar({
        title: t(
          `group:pending_posts_review_success_${pendingPostReviewType.toLowerCase()}`,
        ),
        variant: 'success',
      });
      closeReviewModal();
      setSelected([]);
      onReviewSuccess(variables, pendingPosts);
    },
    onError: () => {
      enqueueSnackbar({
        title: t('group:pending_posts_review_error'),
        variant: 'error',
      });
    },
  });

  const approveSelected = () => {
    showReviewModal({
      type: PendingPostReviewTypes.APPROVE_SELECTED,
      onAction: () =>
        reviewPostsMutation({
          approvalStatus: ApprovalStatus.APPROVED,
          postIds: selected,
        }),
    });
  };

  const rejectSelected = () => {
    showReviewModal({
      type: PendingPostReviewTypes.REJECT_SELECTED,
      onAction: () =>
        reviewPostsMutation({
          approvalStatus: ApprovalStatus.REJECTED,
          postIds: selected,
        }),
    });
  };

  const approveOne = (postId: number) => {
    showReviewModal({
      type: PendingPostReviewTypes.APPROVE_ONE,
      onAction: () =>
        reviewPostsMutation({
          approvalStatus: ApprovalStatus.APPROVED,
          postIds: [postId],
        }),
    });
  };

  const rejectOne = (postId: number) => {
    showReviewModal({
      type: PendingPostReviewTypes.REJECT_ONE,
      onAction: () =>
        reviewPostsMutation({
          approvalStatus: ApprovalStatus.REJECTED,
          postIds: [postId],
        }),
    });
  };

  const handleActionTypeChange = (actionType: PostRequestActionType) => {
    setSelected([]);
    setBulkSelectionMode(false);
    setPage(0);
    onActionTypeChange(actionType);
  };

  const {
    modal: reviewModal,
    showModal: showReviewModal,
    closeModal: closeReviewModal,
  } = useModal<PendingPostReviewModalProps>(({ type, onAction }) => {
    const baseSuffix = type.toLowerCase();
    const editionSuffixByType: Partial<Record<PendingPostReviewTypes, string>> =
      {
        [PendingPostReviewTypes.APPROVE_ONE]: 'approve_edition',
        [PendingPostReviewTypes.REJECT_ONE]: 'reject_edition',
        [PendingPostReviewTypes.APPROVE_SELECTED]: 'approve_selected_edition',
        [PendingPostReviewTypes.REJECT_SELECTED]: 'reject_selected_edition',
      };
    const translationSuffix =
      selectedActionType === PostRequestActionType.EDITION
        ? (editionSuffixByType[type] ?? baseSuffix)
        : baseSuffix;

    return (
      <Dialog
        title={t(`group:pending_post_review_modal_title_${translationSuffix}`, {
          defaultValue: t(
            `group:pending_post_review_modal_title_${baseSuffix}`,
          ),
        })}
        textBody={t(
          `group:pending_post_review_modal_body_${translationSuffix}`,
          {
            defaultValue: t(
              `group:pending_post_review_modal_body_${baseSuffix}`,
            ),
          },
        )}
        primaryButtonProps={{
          onClick: onAction,
          children: t(
            `group:pending_post_review_modal_action_${type.toLowerCase()}`,
          ),
        }}
        secondaryButtonProps={{
          onClick: closeReviewModal,
          children: t('general:cancel'),
        }}
        onClose={closeReviewModal}
      />
    );
  });

  const pendingPosts = data?.items || [];
  const pendingAmount = data?.count || 0;
  const noPendingPosts = !isLoading && pendingAmount === 0;
  const isFirstLoad = isLoading && !data;
  const emptyStateTitle = t('group:no_pending_posts');
  const emptyStateDescription = t('group:no_pending_posts_description');

  return (
    <Stack
      sx={{
        minHeight: '600px',
        height: '100%',
        width: '100%',
        overflowX: 'auto',
      }}
    >
      <Stack
        sx={{
          maxWidth: `${PENDING_POSTS_APPROVAL_WIDTH}px`,
          width: '100%',
          alignSelf: 'center',
          mx: 'auto',
          '.MuiTablePagination-root': {
            overflow: 'unset', // The default overflow: auto caused it to be hidden
          },
          py: 4,
          ...sx,
        }}
      >
        <Typography
          variant="globalL"
          fontWeight="fontWeightSemiBold"
          sx={{ mb: 3 }}
        >
          {t('group:pending_posts_approval', { count: 0 })}
        </Typography>
        <Alert
          severity="info"
          title={t('group:pending_posts_approval_warning')}
          description={t('group:pending_posts_approval_warning_info')}
          sx={{ mb: 4 }}
        />
        <Tabs
          value={selectedActionType}
          tabs={PENDING_REQUEST_TABS.map(tab => ({
            label: t(`post:${tab.labelKey}`),
            value: tab.value,
          }))}
          onTabChange={value =>
            handleActionTypeChange(value as PostRequestActionType)
          }
        />

        {noPendingPosts ? (
          <StateCard
            slotProps={{ card: { sx: { mt: 3 } } }}
            title={emptyStateTitle}
            description={emptyStateDescription}
          />
        ) : (
          <>
            <CardContainer
              sx={{
                p: 2,
                my: 3,
                justifyContent: 'space-between',
                overflow: 'unset',
                '.MuiCardContent-root': {
                  '&:last-child': {
                    p: 0,
                  },
                  display: 'flex',
                  flexDirection: 'row',
                  justifyContent: 'space-between',
                  alignItems: 'center',
                },
              }}
              fullWidth
            >
              <Typography variant="globalS">
                {t('group:pending_posts_approval', { count: pendingAmount })} •{' '}
                {pendingAmount}
              </Typography>
              <Dropdown
                label={t(order)}
                buttonProps={{ disabled: noPendingPosts }}
                open={dropdownOpen}
                onClick={handleDropdownToggle}
              >
                <Stack sx={{ width: 'fit-content', minWidth: 0 }}>
                  {orderByOptions.map(option => (
                    <MenuItem
                      key={option.value}
                      value={option.value}
                      onClick={() => {
                        setOrder(option.value);
                        handleDropdownClose();
                      }}
                    >
                      {option.label}
                    </MenuItem>
                  ))}
                </Stack>
              </Dropdown>
            </CardContainer>
            <Stack
              sx={{
                flexDirection: 'row',
                justifyContent: 'space-between',
                alignItems: 'center',
                mb: 2,
              }}
            >
              <Typography
                variant="globalM"
                fontWeight="fontWeightSemiBold"
              >
                {bulkSelectionMode
                  ? t('group:group_management_of_posts_massive')
                  : selectedActionType === PostRequestActionType.EDITION
                    ? t('group:group_management_of_posts_edition')
                    : t('group:group_management_of_posts')}
              </Typography>
              <Button
                variant="text"
                onClick={toggleBulkSelectionMode}
                disabled={noPendingPosts}
              >
                {bulkSelectionMode ? t('CANCEL') : t('SELECT')}
              </Button>
            </Stack>
          </>
        )}

        {/* Loading state */}
        {isFirstLoad && (
          <Stack sx={{ flexDirection: 'row', justifyContent: 'center', mb: 2 }}>
            <Spinner />
          </Stack>
        )}

        {!noPendingPosts && (
          <Stack
            sx={{
              gap: 2,
            }}
          >
            {pendingPosts.map(pendingPost => (
              <Stack
                key={pendingPost.id}
                sx={{
                  flexDirection: 'row',
                  gap: bulkSelectionMode ? 2 : 0,
                }}
              >
                <Box
                  sx={{
                    width: bulkSelectionMode ? '38px' : '0px',
                    overflow: 'hidden',
                    transition: 'width 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
                    display: 'flex',
                    alignItems: 'center',
                    flexShrink: 0,
                  }}
                >
                  <Checkbox
                    checked={selected.includes(pendingPost.id)}
                    onChange={() => {
                      if (selected.includes(pendingPost.id)) {
                        setSelected(
                          selected.filter(id => id !== pendingPost.id),
                        );
                      } else {
                        setSelected(_selected => [
                          ..._selected,
                          pendingPost.id,
                        ]);
                      }
                    }}
                  />
                </Box>
                <Stack
                  sx={{
                    flex: 1,
                    minWidth: 0,
                  }}
                >
                  <PendingPostCard
                    key={pendingPost.id}
                    pendingPost={pendingPost}
                    onApprove={approveOne}
                    onReject={rejectOne}
                  />
                </Stack>
              </Stack>
            ))}
          </Stack>
        )}
        {!noPendingPosts && paginationController(pendingAmount)}
        {selected.length > 0 && (
          <Stack
            sx={{
              position: 'fixed',
              bottom: 0,
              left: 0,
              right: 0,
              zIndex: 1,
              backgroundColor: theme =>
                theme.palette.new.background.layout.tertiary,
              alignItems: 'center',
            }}
          >
            <Stack
              sx={{
                width: `${PENDING_POSTS_APPROVAL_WIDTH}px`,
                py: 2,
                gap: 4.5,
                flexDirection: 'row',
                justifyContent: 'space-between',
              }}
            >
              <Typography
                variant="subtitle1"
                fontWeight="500"
              >
                {t('group:selected_posts')}: {selected.length}/{pendingAmount}
              </Typography>
              <Stack sx={{ flexDirection: 'row', gap: 2 }}>
                <Button
                  variant="tertiary"
                  onClick={rejectSelected}
                >
                  {t('group:reject')}
                </Button>
                <Button
                  variant="primary"
                  onClick={approveSelected}
                >
                  {t('group:approve')}
                </Button>
              </Stack>
            </Stack>
          </Stack>
        )}
        {reviewModal}
      </Stack>
    </Stack>
  );
};

const PendingPostsApprovalThemeProvider = (props: Props) => {
  const HugoThemeProvider = useHuGoTheme();
  return (
    <HugoThemeProvider>
      <PendingPostsApproval {...props} />
    </HugoThemeProvider>
  );
};

export default PendingPostsApprovalThemeProvider;
