import {
  type FC,
  Suspense,
  useCallback,
  useEffect,
  useRef,
  useState,
} from 'react';
import { Helmet } from 'react-helmet-async';
import { useInView } from 'react-intersection-observer';
import { useLocation, useNavigate } from 'react-router-dom';

import { StreamVideo } from '@stream-io/video-react-sdk';
import { IconSettings } from '@material-hu/icons/tabler';
import Box from '@material-hu/mui/Box';
import Container from '@material-hu/mui/Container';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';
import useMediaQuery from '@material-hu/mui/useMediaQuery';

import HuBadge from '@material-hu/components/design-system/Badge';
import HuSpinner from '@material-hu/components/design-system/ProgressIndicators/Spinner';

import { logEvent } from 'src/config/logging';
import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useAuth } from 'src/contexts/JWTContext';
import {
  NewPostNotificationProvider,
  useNewPostNotification,
} from 'src/contexts/NewPostNotificationContext';
import { useSocket } from 'src/contexts/SocketContext';
import useCommunityFeature from 'src/hooks/useCommunityFeature';
import useCustomServerTranslation from 'src/hooks/useCustomServerTranslation';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import useNewTheme from 'src/hooks/useNewTheme';
import usePermissions from 'src/hooks/usePermissions';
import {
  addFeedAndPinListDataReaction,
  addPinnedPost,
  isPostInFeedCache,
  postCreated,
  postDeleted,
  refetchAllPendingApprovalPostRequests,
  refetchAllPosts,
  removeFeedAndPinListDataReaction,
  removePinnedPost,
} from 'src/pages/dashboard/feed/queries';
import useGetStreamVideoClient from 'src/pages/dashboard/liveStream/hooks/useGetStreamVideoClient';
import { EventName } from 'src/types/amplitude';
import { CommunityFeature } from 'src/types/communityFeatures';
import { FeedSource } from 'src/types/feed';
import { type Post, type PostReactionSocket } from 'src/types/posts';
import { UserTypeStream } from 'src/types/stream';
import { formatTitle } from 'src/utils/helmetUtils';
import { lazyRetry } from 'src/utils/lazyRetry';
import { UserPermissions } from 'src/utils/permissions';

import { ExternalToolsCard } from 'src/components/dashboard/externalTools/ExternalToolsCard';
import WidgetsCard from 'src/components/dashboard/widgets/WidgetsCard';
import KeyUpdatesAlert from 'src/components/key-updates/KeyUpdatesAlert';
import PendingApprovalPostList from 'src/components/pendingApprovals/PendingApprovalPostList';

import useAttachCommonGroupListeners from '../groups/hooks/useAttachCommonGroupListeners';

import PostAddSkeleton from './components/PostAddSkeleton';
import useScheduledPostsDrawer from './components/schedule/useScheduledPostsDrawer';
import { useFeedHasPendingPostRequests } from './hooks/useFeedHasPendingPostRequests';
import { feedRoutes } from './routes';

const NewPostsButton = lazyRetry(() => import('./components/NewPostsButton'));
const PostAdd = lazyRetry(() => import('./components/PostAdd'));
const PostList = lazyRetry(() => import('./components/PostList'));
const PostSearch = lazyRetry(() => import('./components/FeedPostSearch'));
const SchedulePostFeedback = lazyRetry(
  () => import('./components/schedule/SchedulePostFeedback'),
);
const UpcomingCelebrationsCard = lazyRetry(() =>
  import('src/components/dashboard/upcomingCelebrations').then(module => ({
    default: module.UpcomingCelebrationsCard,
  })),
);
const UpcomingCelebrationsAccordion = lazyRetry(() =>
  import('src/components/dashboard/upcomingCelebrations').then(module => ({
    default: module.UpcomingCelebrationsAccordion,
  })),
);

const { VIEW_BIRTHDAYS, VIEW_ANNIVERSARIES, VIEW_WIDGET } = UserPermissions;

const SMALL_SCREEN = 1075;

const FeedContent: FC = () => {
  const socket = useSocket();
  const { user } = useAuth();
  const navigate = useNavigate();
  const { hasNewPosts, onAddNewPost, onRemoveNewPosts } =
    useNewPostNotification();
  const client = useGetStreamVideoClient(UserTypeStream.VIEWER);
  const theme = useTheme();
  const location = useLocation();
  const NewThemeProvider = useNewTheme();
  const HugoThemeProvider = useHuGoTheme();
  const title = useCustomServerTranslation({
    module: 'FEED',
    defaultTranslationKey: 'post:feed',
  });
  const { state } = location;
  const scheduledKey = (state as any)?.id;

  const canViewGroupPostsInFeed = useCommunityFeature(
    CommunityFeature.VIEW_GROUP_POSTS_IN_FEED,
  );
  const { hasAny: canViewCelebrations } = usePermissions([
    VIEW_BIRTHDAYS,
    VIEW_ANNIVERSARIES,
  ]);
  const { hasAll: canViewWidgets } = usePermissions([VIEW_WIDGET]);
  const { hasAll: canApprovePendingPosts } = usePermissions([
    UserPermissions.CAN_APPROVE_FEED_POSTS,
  ]);

  const { hasAll: canViewKeyUpdates } = usePermissions([
    UserPermissions.VIEW_KEY_UPDATES,
  ]);

  const { data: hasPendingPostRequests } = useFeedHasPendingPostRequests();

  const isSmallScreen = useMediaQuery(theme.breakpoints.down(SMALL_SCREEN));

  // eslint-disable-next-line react/hook-use-state
  const [, setRerenderPage] = useState({});
  const [showButton, setShowButton] = useState(false);

  const { drawer, showDrawer } = useScheduledPostsDrawer();

  const messagesEndRef = useRef<HTMLElement | null>(null);
  const celebrationsRef = useRef<HTMLElement | null>(null);

  const { ref: setMessagesEndRef, inView: inViewMessagesEnd } = useInView();
  const { ref: setCelebrationsRef, inView: inViewCelebrations } = useInView();

  const setRef = useCallback(
    (node: HTMLElement | null) => {
      messagesEndRef.current = node;

      setMessagesEndRef(node);
    },
    [setMessagesEndRef],
  );

  const setCelebrationRef = useCallback(
    (node: HTMLElement | null) => {
      celebrationsRef.current = node;

      setCelebrationsRef(node);
    },
    [setCelebrationsRef],
  );

  useEffect(() => {
    if (hasNewPosts) {
      setShowButton(true);
    }
  }, [hasNewPosts]);

  useEffect(() => {
    if (inViewMessagesEnd && showButton) {
      setShowButton(false);
      postCreated();
      onRemoveNewPosts();
    }
  }, [inViewMessagesEnd, showButton]);

  useEffect(() => {
    if (scheduledKey !== 'schedulePost') {
      return;
    }
    showDrawer({});
    window.history.replaceState({}, document.title);
  }, [scheduledKey]);

  useEffect(() => {
    if (canViewCelebrations) logEvent(EventName.BIRTHDAYS_VIEW);
  }, [canViewCelebrations]);

  const handleRemoveNewPost = () => {
    postDeleted();
    onRemoveNewPosts();
  };

  useEffect(() => {
    let handleResize: (() => void) | null = null;

    // Lazy load debounce when needed
    const setupResizeHandler = async () => {
      const { default: debounce } = await import('lodash/debounce');
      handleResize = debounce(() => {
        setRerenderPage({});
      }, 50);

      window.addEventListener('resize', handleResize);
    };

    setupResizeHandler();

    return () => {
      if (handleResize) {
        window.removeEventListener('resize', handleResize);
      }
    };
  }, []);

  useAttachCommonGroupListeners({
    enabled: canViewGroupPostsInFeed,
    source: FeedSource.FEED,
    onAddNewPost,
  });

  useEffect(() => {
    const addNewReaction = (reaction: PostReactionSocket) => {
      const { emoji, unified, userId, postId } = reaction;

      addFeedAndPinListDataReaction(
        postId,
        emoji,
        unified,
        userId === user?.id,
      );
    };

    const removePostReaction = (reaction: PostReactionSocket) => {
      const { emoji, userId, postId } = reaction;

      removeFeedAndPinListDataReaction(postId, emoji, userId === user?.id);
    };

    const handlePinPost = (post: Post) => {
      addPinnedPost(post);
    };

    const updatePostRequests = () => {
      refetchAllPendingApprovalPostRequests();
      refetchAllPosts();
    };

    socket.listenEvent(EVENTS_SOCKETS.NEW_POST_REACTION, addNewReaction);
    socket.listenEvent(EVENTS_SOCKETS.REMOVE_POST_REACTION, removePostReaction);
    socket.listenEvent(EVENTS_SOCKETS.POST_PINNED, handlePinPost);
    socket.listenEvent(EVENTS_SOCKETS.POST_UNPINNED, removePinnedPost);
    socket.listenEvent(EVENTS_SOCKETS.POST_DELETED, handleRemoveNewPost);
    socket.listenEvent(
      EVENTS_SOCKETS.POST_REQUEST_APPROVED,
      updatePostRequests,
    );
    socket.listenEvent(
      EVENTS_SOCKETS.POST_REQUEST_REJECTED,
      refetchAllPendingApprovalPostRequests,
    );

    return () => {
      socket.closeEvent(EVENTS_SOCKETS.NEW_POST_REACTION, addNewReaction);
      socket.closeEvent(
        EVENTS_SOCKETS.REMOVE_POST_REACTION,
        removePostReaction,
      );
      socket.closeEvent(EVENTS_SOCKETS.POST_PINNED, handlePinPost);
      socket.closeEvent(EVENTS_SOCKETS.POST_UNPINNED, removePinnedPost);
      socket.closeEvent(EVENTS_SOCKETS.POST_DELETED, handleRemoveNewPost);
      socket.closeEvent(EVENTS_SOCKETS.POST_REQUEST_APPROVED, refetchAllPosts);
      socket.closeEvent(
        EVENTS_SOCKETS.POST_REQUEST_REJECTED,
        refetchAllPendingApprovalPostRequests,
      );
    };
  }, [socket, user?.id, inViewMessagesEnd]);

  useEffect(() => {
    const addNewPost = (post: Post) => {
      if (user?.id !== post.user.id || !isPostInFeedCache(post.id)) {
        onAddNewPost();
      }
    };

    const removePost = () => postDeleted();

    socket.listenEvent(EVENTS_SOCKETS.POST_CREATED, addNewPost);
    socket.listenEvent(EVENTS_SOCKETS.POST_DELETED, removePost);

    return () => {
      socket.closeEvent(EVENTS_SOCKETS.POST_CREATED, addNewPost);
      socket.closeEvent(EVENTS_SOCKETS.POST_DELETED, removePost);
    };
  }, [socket, user?.id, onAddNewPost]);

  const messagesStartRef = useRef<HTMLElement | null>(null);

  const scrollToTop = () => {
    messagesStartRef.current?.scrollIntoView({
      block: 'start',
      behavior: 'smooth',
    });
  };

  const handleNewPosts = () => {
    setShowButton(false);
    scrollToTop();
    postCreated();
    onRemoveNewPosts();
  };

  useEffect(() => {
    const dashboardLayout = document.getElementById('dashboard-layout-content');
    if (!dashboardLayout) return;

    const onScroll = () => {
      const sideModules = document.getElementById('side-modules');
      if (sideModules && dashboardLayout) {
        sideModules.style.paddingTop =
          dashboardLayout.scrollTop > 60 ? '0px' : '32px';
      }
    };
    dashboardLayout.addEventListener('scroll', onScroll);

    return () => dashboardLayout.removeEventListener('scroll', onScroll);
  }, []);

  const navigateToFeedPendingPosts = () => {
    navigate(feedRoutes.pendingPosts());
  };

  const celebrationsPositionShouldBeFixed =
    !inViewCelebrations || !canViewCelebrations;

  return (
    <StreamVideo client={client}>
      <Helmet>
        <title>{formatTitle(title)}</title>
      </Helmet>
      <HugoThemeProvider>
        <Box
          ref={messagesStartRef}
          sx={{
            backgroundColor: theme =>
              theme.palette.new.background.layout.default,
            minHeight: '100%',
            pt: 2,
            pb: 8,
          }}
        >
          <Stack
            direction="row"
            justifyContent="center"
          >
            {/* TODO: migrate to HuContainer */}
            <Container
              maxWidth="sm"
              id="feed-container"
              sx={{
                position: 'relative',
                mx: 0,
                pt: 4,
                pr:
                  canViewCelebrations && !isSmallScreen
                    ? '0 !important'
                    : undefined,
              }}
            >
              {canViewKeyUpdates && (
                <Stack sx={{ mb: 3 }}>
                  <KeyUpdatesAlert />
                </Stack>
              )}
              <Box
                id="search-container"
                sx={{
                  display: 'flex',
                  flexDirection: 'row',
                  justifyContent: 'space-between',
                  alignItems: 'center',
                }}
              >
                <Typography
                  color={theme => theme.palette.new.text.neutral.default}
                  variant="globalXL"
                  fontWeight="semiBold"
                >
                  {title}
                </Typography>
                <Stack sx={{ flexDirection: 'row', gap: 1 }}>
                  <Suspense fallback={<HuSpinner sx={{ p: 1 }} />}>
                    <PostSearch />
                  </Suspense>
                  {canApprovePendingPosts && (
                    <IconButton
                      onClick={navigateToFeedPendingPosts}
                      variant="secondary"
                      sx={{ py: 0 }}
                    >
                      <Stack
                        sx={{
                          color: theme =>
                            theme.palette.new.text.neutral.default,
                          flexDirection: 'row',
                        }}
                      >
                        <IconSettings
                          width={16}
                          height={16}
                        />
                        {hasPendingPostRequests && (
                          <HuBadge
                            variant="dot"
                            color="primary"
                            sx={{ mt: 1, ml: 1, mr: 0.5 }}
                          />
                        )}
                      </Stack>
                    </IconButton>
                  )}
                </Stack>
              </Box>
              <Stack sx={{ mt: 3, gap: 2 }}>
                <Suspense fallback={<PostAddSkeleton />}>
                  <PostAdd onScheduledPostView={() => showDrawer({})} />
                </Suspense>
                <PendingApprovalPostList />
                <SchedulePostFeedback onSeePosts={() => showDrawer({})} />
                {canViewCelebrations && isSmallScreen && (
                  <NewThemeProvider>
                    <Suspense fallback={<HuSpinner sx={{ p: 1 }} />}>
                      <UpcomingCelebrationsAccordion />
                    </Suspense>
                  </NewThemeProvider>
                )}
              </Stack>
              {drawer}
              <Box ref={setRef} />
              {showButton && (
                <Suspense fallback={<HuSpinner sx={{ p: 1 }} />}>
                  <NewPostsButton
                    inViewMessagesEnd={inViewMessagesEnd}
                    onClick={handleNewPosts}
                  />
                </Suspense>
              )}
              <Box>
                <Suspense fallback={<HuSpinner sx={{ p: 1 }} />}>
                  <PostList />
                </Suspense>
              </Box>
            </Container>
            {(canViewCelebrations || canViewWidgets) && !isSmallScreen && (
              // TODO: migrate to HuContainer
              <Container
                id="side-modules"
                sx={{
                  maxWidth: '400px !important',
                  margin: '0 !important',
                  pt: 4,
                  transition: 'padding 0.3s',
                }}
              >
                {canViewCelebrations && (
                  <Box
                    ref={setCelebrationRef}
                    sx={{
                      height: '510px',
                      position: canViewWidgets ? 'static' : 'fixed',
                      mb: 2,
                    }}
                  >
                    <Suspense fallback={<HuSpinner sx={{ p: 1 }} />}>
                      <UpcomingCelebrationsCard />
                    </Suspense>
                  </Box>
                )}
                <Stack
                  sx={{
                    flexDirection: 'column',
                    gap: 2,
                    position: celebrationsPositionShouldBeFixed
                      ? 'fixed'
                      : 'relative',
                    top:
                      canViewCelebrations && !inViewCelebrations
                        ? '76px'
                        : 'unset',
                  }}
                >
                  <WidgetsCard />
                  <ExternalToolsCard />
                </Stack>
              </Container>
            )}
          </Stack>
        </Box>
      </HugoThemeProvider>
    </StreamVideo>
  );
};

const Feed: FC = () => {
  return (
    <NewPostNotificationProvider>
      <FeedContent />
    </NewPostNotificationProvider>
  );
};

export default Feed;
