import cx from 'classnames';
import get from 'lodash/get';
import React, { useMemo } from 'react';

import { ChatContext, IChatContext, withContext } from 'context';
import {
  ChannelIdentityFragment,
  DmIdentityFragment,
  UserChannelsPreviewComponent,
  UserDmsPreviewComponent,
} from 'shared/graphql/__generated__';
import { getDmName } from 'shared/utils';

import css from './chat-window.module.css';
import Body from './components/body';
import Footer from './components/footer';
import Header from './components/header';

// -- TYPES

interface IChatWindowProps
  extends Pick<
    IChatContext,
    | 'setChannel'
    | 'setTabs'
    | 'setSidebarVisibility'
    | 'user'
    | 'isSidebarVisible'
    | 'channelMembersFilter'
  > {
  channelIdentityId?: string;
  isTab?: boolean;
  isTabCollapsed?: boolean;
  style?: React.CSSProperties;
}

type MergedChannelIdentity = ChannelIdentityFragment & DmIdentityFragment;

// -- MAIN

function ChatWindow({
  channelIdentityId,
  user,
  setChannel,
  setSidebarVisibility,
  setTabs,
  isSidebarVisible,
  isTab,
  isTabCollapsed,
  style,
  channelMembersFilter,
}: IChatWindowProps) {
  const cn = cx(isTab ? (isTabCollapsed ? css['shrinked-tab'] : css.tab) : css.window);

  const cnBody = useMemo(
    () => ({
      wrapper: cx(isTabCollapsed && css.hidden, css['horizontal-padding']),
    }),
    [isTabCollapsed],
  );

  const cnFooter = cx(isTabCollapsed && css.hidden, css['horizontal-padding']);

  return (
    <UserChannelsPreviewComponent
      variables={{ channelMembersFilter }}
      fetchPolicy="cache-only"
    >
      {({ data: channelsData }) => (
        <UserDmsPreviewComponent
          variables={{ channelMembersFilter }}
          fetchPolicy="cache-only"
        >
          {({ data: dmsData }) => {
            const channelIdentities: ChannelIdentityFragment[] = get(
              channelsData,
              'user.channelIdentities.items',
              [],
            );

            const dmIdentities: DmIdentityFragment[] = get(
              dmsData,
              'user.channelIdentities.items',
              [],
            );

            const identities = [...channelIdentities, ...dmIdentities];

            const identity: Partial<MergedChannelIdentity> =
              identities.find(el => el.id === channelIdentityId) || {};

            const channel: Partial<MergedChannelIdentity['channel']> =
              identity.channel || {};

            const userId = user && user.id;
            const createdById = get(channel, ['createdBy', 'id']);
            const isChannel = channel.type === 'channel';
            const isOwner = createdById === userId;
            const canEdit = isChannel && (channel.public || isOwner);

            const channelName = isChannel
              ? channel.name
              : channel.members && userId
              ? getDmName(channel.members, userId)
              : '';

            return (
              <div className={cn} style={style}>
                <Header
                  className={css['horizontal-padding']}
                  channelId={channel.id}
                  channelName={channelName}
                  channelIdentityId={identity.id}
                  canEdit={canEdit}
                  isChannel={isChannel}
                  setChannel={setChannel}
                  setTabs={setTabs}
                  setSidebarVisibility={setSidebarVisibility}
                  isSidebarVisible={isSidebarVisible}
                  isTab={isTab}
                  isOwner={isOwner}
                />

                <Body
                  className={cnBody}
                  channelId={channel.id}
                  channelIdentityId={identity.id}
                  userId={userId}
                  hasUnreads={identity.hasUnreads}
                  isHidden={isTabCollapsed}
                />

                {user && (
                  <Footer className={cnFooter} channelId={channel.id} userId={user.id} />
                )}
              </div>
            );
          }}
        </UserDmsPreviewComponent>
      )}
    </UserChannelsPreviewComponent>
  );
}

export default withContext<IChatWindowProps, IChatContext>({
  context: ChatContext,
  keys: [
    'setChannel',
    'setTabs',
    'setSidebarVisibility',
    'user',
    'isSidebarVisible',
    'channelMembersFilter',
  ],
})(ChatWindow);
