import { FC, ReactNode, Fragment, useState, useEffect, useMemo } from 'react';
import { useMutation } from 'react-query';
import {
  useNavigate,
  useParams,
  useMatch,
  matchPath,
  useLocation,
} from 'react-router-dom';

import { useModal } from '@material-hu/hooks/useModal';
import CallOutlinedIcon from '@material-hu/icons/material/CallOutlined';
import VideocamOutlinedIcon from '@material-hu/icons/material/VideocamOutlined';
import Box from '@material-hu/mui/Box';
import ButtonBase from '@material-hu/mui/ButtonBase';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import useMediaQuery from '@material-hu/mui/useMediaQuery';

import useSnackbar from '@material-hu/components/design-system/Snackbar';

import { useAuth } from 'src/contexts/JWTContext';
import { useSidebar } from 'src/contexts/SidebarContext';
import useCommunityFeature from 'src/hooks/useCommunityFeature';
import useNewTheme from 'src/hooks/useNewTheme';
import { ticketRoutes } from 'src/pages/dashboard/tickets/routes';
import { ticketSkeletonRoutes } from 'src/pages/dashboard/tickets/routes';
import { MAX_CALL_PARTICIPANTS } from 'src/pages/dashboard/videoCall/constants';
import { createVideoCall } from 'src/services/streaming';
import { ChatListItem, ChatType } from 'src/types/chats';
import { CommunityFeature } from 'src/types/communityFeatures';
import { FormType } from 'src/types/forms';
import { InitializationConfig } from 'src/types/stream';
import { User } from 'src/types/user';
import { getStringFromParticipantsArray } from 'src/utils/chats';
import { getUrl } from 'src/utils/stream';

import ChatAvatar from 'src/components/dashboard/chat/ChatAvatar';
import ChatName from 'src/components/dashboard/chat/ChatName';
import { CHATS_SIDEBAR_WIDTH } from 'src/components/dashboard/chat/ChatsSidebar';
import { useTranslation } from 'src/components/dashboard/chat/i18n';
import { chatRoutes } from 'src/components/dashboard/chat/routes';
import { chatSkeletonRoutes } from 'src/components/dashboard/chat/routes';
import { formRoutes } from 'src/components/dashboard/form/routes';
import { formSkeletonRoutes } from 'src/components/dashboard/form/routes';
import GoBackButton from 'src/components/dashboard/GoBackButton';
import FeatureNotAvailableModal, {
  FeaturesNotAvailable,
} from 'src/components/FeatureNotAvailableModal';
import GettingReadyModal from 'src/components/FeatureNotAvailableModal/GettingReadyModal';

import ToolbarMenu from './ToolbarMenu';

const CHAT_PATH = chatSkeletonRoutes.thread.detail();
const TICKETS_PATH = ticketSkeletonRoutes.thread.detail();
const REQUEST_PATH = formSkeletonRoutes.requests.general(FormType.FORM);
const SURVEY_PATH = formSkeletonRoutes.form.chat(FormType.SURVEY);
const FORM_PATH = formSkeletonRoutes.forms(FormType.FORM);

export type ToolbarMenuOption = {
  id: string;
  enabled?: boolean;
  option: ReactNode;
};

export type ChatThreadToolbarProps = {
  thread: ChatListItem;
  menuOptions?: ToolbarMenuOption[];
  otherUser?: User;
  OnOpenGroupInfo?: () => void;
  participants?: User[];
  isGroupInfoOpen?: boolean;
};

const ChatThreadToolbar: FC<ChatThreadToolbarProps> = props => {
  const {
    thread,
    menuOptions = [],
    otherUser,
    OnOpenGroupInfo,
    participants,
    isGroupInfoOpen,
  } = props;
  const isGroup = thread?.chatType === ChatType.REGULAR_GROUP;

  const [initialize, setInitialize] = useState(isGroup);
  const NewThemeProvider = useNewTheme();
  const navigate = useNavigate();
  const location = useLocation();
  const { id } = useParams();
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
  const isDownMd = useMediaQuery(theme.breakpoints.down('md'));
  const { user, instance } = useAuth();
  const { t } = useTranslation();
  const { enqueueSnackbar } = useSnackbar();
  const canCall = useCommunityFeature(CommunityFeature.VIEW_CALL);

  const { width } = useSidebar();

  const isForm = thread?.chatType === ChatType.FORM;
  const isTicket = thread?.chatType === ChatType.TICKET;

  const viewUser = useMatch(formRoutes.form.chat(FormType.FORM, id));

  const filteredOptions = menuOptions.filter(option => option.enabled);

  const isChatThread = !!matchPath(
    {
      path: CHAT_PATH,
      end: false,
    },
    location.pathname,
  );

  const isTicketThread = !!matchPath(
    {
      path: TICKETS_PATH,
      end: false,
    },
    location.pathname,
  );

  const isRequestThread = !!matchPath(
    {
      path: REQUEST_PATH,
      end: false,
    },
    location.pathname,
  );

  const isFormThread = !!matchPath(
    {
      path: FORM_PATH,
      end: false,
    },
    location.pathname,
  );

  const isSurveyThread = !!matchPath(
    {
      path: SURVEY_PATH,
      end: false,
    },
    location.pathname,
  );

  const { mutateAsync: initCall } = useMutation(
    ({
      chatId,
      initializationConfig,
    }: {
      chatId: number;
      initializationConfig: InitializationConfig;
    }) => createVideoCall({ chatId, initializationConfig }),
    {
      onSuccess: data => {
        const { data: callData } = data;

        window.open(
          getUrl({
            id: callData.id,
            providerCallId: callData.providerCallId,
            emitCall: true,
            initAndJoinCall: isGroup, // when we emit a group call we need to init and join the call
          }),
        );
      },
      onError: () => {
        enqueueSnackbar({
          title: t('VIDEOCALL:ERROR_INIT_CALL'),
          variant: 'error',
        });
      },
    },
  );

  useEffect(() => {
    if (initialize) {
      const timeOutId = setTimeout(() => setInitialize(false), 3000);
      return () => clearTimeout(timeOutId);
    }
  }, [initialize]);

  const threadInfoWidth =
    document.getElementById('chat-thread-info-drawer')?.offsetWidth || 0;

  const oneMemberGroup = isGroup && participants?.length === 1;
  const isCallEnabled =
    (instance?.allowChatCall || canCall) &&
    !(isForm || isTicket) &&
    (participants?.length ?? 0) <= MAX_CALL_PARTICIPANTS &&
    !oneMemberGroup;

  const chatNameWidth = useMemo(() => {
    if (isGroup) {
      const threadToolbarIconAndMarginWidth = 120;
      const sumComponentWidth =
        width +
        CHATS_SIDEBAR_WIDTH +
        (isGroupInfoOpen ? threadInfoWidth : 0) +
        (isCallEnabled ? 80 : 0) +
        threadToolbarIconAndMarginWidth;
      return isDownMd
        ? 'calc(100vw - 240px)'
        : `calc(100vw - ${sumComponentWidth}px)`;
    }
  }, [isGroup, threadInfoWidth, width, isGroupInfoOpen, isDownMd]);

  const chatNameMinWidth = useMemo(() => {
    if (isGroup) {
      return isMobile ? 'auto' : 300;
    }
  }, [isGroup]);

  const subtitle = useMemo(() => {
    if (isGroup) {
      return initialize
        ? t('CLICK_TO_SEE_INFO_GROUP')
        : getStringFromParticipantsArray(participants, user, t);
    }
  }, [isGroup, initialize, participants]);

  const handleBack = e => {
    e.stopPropagation();
    e.preventDefault();
    if (isChatThread) {
      navigate(chatRoutes.chats());
    }
    if (isTicketThread) {
      navigate(ticketRoutes.tickets());
    }
    if (isRequestThread) {
      navigate(formRoutes.requests.general(thread.form?.type));
    } else if (isFormThread || isSurveyThread) {
      navigate(formRoutes.forms(thread.form?.type), {
        state: {
          toCompletedTab: 1,
        },
      });
    }
  };

  const enabledSeeBackButton =
    isMobile || (isForm && (viewUser || thread.form?.type === FormType.SURVEY));

  const {
    modal: featureNotAvailableModal,
    showModal: showfeatureNotAvailableModal,
    closeModal,
  } = useModal(({ featureName }: { featureName: FeaturesNotAvailable }) => (
    <FeatureNotAvailableModal
      featureName={featureName}
      onAccept={closeModal}
    />
  ));

  const {
    modal: gettingReadyModal,
    showModal: showGettingReadyModal,
    closeModal: closeGettingReadyModal,
  } = useModal(
    ({
      isVideoCall,
      onAbort,
    }: {
      isVideoCall: boolean;
      onAbort: () => void;
    }) => (
      <GettingReadyModal
        isVideoCall={isVideoCall}
        onClose={closeGettingReadyModal}
        onAbort={onAbort}
      />
    ),
    { disableEscapeKeyDown: true },
  );

  const handleFeatureNotAvailable = (featureName: FeaturesNotAvailable) => {
    const timeout = setTimeout(() => {
      closeGettingReadyModal();
      showfeatureNotAvailableModal({ featureName });
    }, 10000);
    showGettingReadyModal({
      isVideoCall: featureName === 'VIDEO_CALL',
      onAbort: () => clearTimeout(timeout),
    });
  };

  const callToUser = (initializationConfig: InitializationConfig) =>
    initCall({ chatId: Number(id), initializationConfig });

  return (
    <NewThemeProvider>
      <Box
        id="chat-toolbar"
        className="toolbar"
      >
        {featureNotAvailableModal}
        {gettingReadyModal}
        <ButtonBase
          onClick={isGroup ? OnOpenGroupInfo : () => {}}
          sx={{
            width: '100%',
            cursor: isGroup ? 'pointer' : 'default',
          }}
          disableTouchRipple
        >
          {enabledSeeBackButton && (
            <GoBackButton
              sx={{
                alignSelf: 'center',
                mr: 1,
                minWidth: '40px',
                maxWidth: '40px',
              }}
              onClick={handleBack}
            />
          )}
          <ChatAvatar
            thread={thread}
            className="avatar"
            otherUser={otherUser}
            withUserDeleted
            isChatToolbar
          />
          <ChatName
            thread={thread}
            className="name"
            otherUser={otherUser}
            withUserDeleted
            isChatToolbar
            subtitle={subtitle}
            width={chatNameWidth}
            minWidth={chatNameMinWidth}
          />
        </ButtonBase>
        {isCallEnabled && (
          <Stack sx={{ flexDirection: 'row' }}>
            <IconButton>
              <CallOutlinedIcon
                onClick={() => {
                  if (canCall) {
                    callToUser({ cameraEnabled: false });
                    return;
                  }
                  handleFeatureNotAvailable(FeaturesNotAvailable.CALL);
                }}
              />
            </IconButton>
            <IconButton>
              <VideocamOutlinedIcon
                onClick={() => {
                  if (canCall) {
                    callToUser({ cameraEnabled: true });
                    return;
                  }
                  handleFeatureNotAvailable(FeaturesNotAvailable.VIDEO_CALL);
                }}
              />
            </IconButton>
          </Stack>
        )}
        {filteredOptions.length > 0 && (
          <ToolbarMenu>
            <Box>
              {filteredOptions.map(({ option, id: optionId }) => (
                <Fragment key={optionId}>{option}</Fragment>
              ))}
            </Box>
          </ToolbarMenu>
        )}
      </Box>
    </NewThemeProvider>
  );
};

export default ChatThreadToolbar;
