import { Button, Dialog, ModalContext } from '@8base/boost';
import React from 'react';
import { compose } from 'react-apollo';

import { DataProxy } from 'apollo-cache';
import {
  ChannelDeleteMutationFn,
  UserChannelsPreviewDocument,
  UserChannelsPreviewQuery,
  UserChannelsPreviewQueryVariables,
  UserDmsPreviewDocument,
  UserDmsPreviewQuery,
  UserDmsPreviewQueryVariables,
  withChannelDelete,
} from 'shared/graphql/__generated__';
import { ChatContext, IChatContext, withContext } from '../../../context';

// -- TYPES

interface IDeleteChannelDialogProps {
  deleteChannel: ChannelDeleteMutationFn;
  channelMembersFilter: IChatContext['channelMembersFilter'];
}

export interface IDeleteDialogData {
  channelId: string;
  isChannel: boolean;
  onDelete: () => void;
}

interface IDialogProps extends IDeleteChannelDialogProps, IDeleteDialogData {}

// -- CONSTANTS

export const DELETE_CHANNEL_DIALOG_ID = 'DELETE_CHANNEL_DIALOG_ID';

// -- MAIN

class DialogContent extends React.Component<IDialogProps> {
  static contextType = ModalContext;

  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <Dialog.Header title="Delete channel" onClose={this.closeDialog} />

        <Dialog.Body scrollable={true}>
          Do you really want to delete this channel?
        </Dialog.Body>

        <Dialog.Footer>
          <Button color="neutral" variant="outlined" onClick={this.closeDialog}>
            Cancel
          </Button>
          <Button color="danger" type="submit">
            Delete
          </Button>
        </Dialog.Footer>
      </form>
    );
  }

  private onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    const { deleteChannel, channelId, onDelete, channelMembersFilter } = this.props;

    deleteChannel({
      variables: {
        id: channelId,
      },
      optimisticResponse: {
        channelDelete: {
          __typename: 'SuccessResponse',
          success: true,
        },
      },
      update: (cache, { data }) => {
        if (!data || !data.channelDelete || !data.channelDelete.success) {
          return;
        }

        const updateCache = (
          userChannelsPreview: UserDmsPreviewQuery | UserChannelsPreviewQuery,
        ): UserDmsPreviewQuery | UserChannelsPreviewQuery => {
          const channelIdentities = userChannelsPreview.user!.channelIdentities!;
          channelIdentities.items = channelIdentities.items.filter(
            channelMember => channelMember.channel!.id !== channelId,
          );
          return userChannelsPreview;
        };

        const { isChannel } = this.props;

        if (isChannel) {
          this.updateCache<UserChannelsPreviewQuery, UserChannelsPreviewQueryVariables>(
            cache,
            UserChannelsPreviewDocument,
            updateCache,
            { channelMembersFilter },
          );
        } else {
          this.updateCache<UserDmsPreviewQuery, UserDmsPreviewQueryVariables>(
            cache,
            UserDmsPreviewDocument,
            updateCache,
            { channelMembersFilter },
          );
        }
      },
    });

    onDelete();
    this.closeDialog();
  };

  private updateCache<QResponse, QVariables>(
    cache: DataProxy,
    query: string,
    update: (preview: any) => any,
    variables?: QVariables,
  ) {
    let queryPreview;
    try {
      queryPreview = cache.readQuery<QResponse, QVariables>({
        query,
        variables,
      });
    } catch (e) {
      return;
    }

    if (!queryPreview) {
      return;
    }

    const cachedDataUpdated = update(queryPreview);

    cache.writeQuery<QResponse, QVariables>({
      query,
      variables,
      data: cachedDataUpdated,
    });
  }

  private closeDialog = () => {
    this.context.closeModal(DELETE_CHANNEL_DIALOG_ID);
  };
}

function DeleteChannelDialog(props: IDeleteChannelDialogProps) {
  return (
    <Dialog id={DELETE_CHANNEL_DIALOG_ID} size="sm">
      {({ args }: { args: IDeleteDialogData }) => <DialogContent {...props} {...args} />}
    </Dialog>
  );
}

DeleteChannelDialog.id = DELETE_CHANNEL_DIALOG_ID;

export default compose(
  withChannelDelete<{}, IDeleteChannelDialogProps>({
    name: 'deleteChannel',
  }),
  withContext({ context: ChatContext, keys: ['channelMembersFilter'] }),
)(DeleteChannelDialog);
