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

import { getOperationName } from 'apollo-link';
import { ChatContext, IChatContext, withContext } from 'context';
import { DialogForm, UserSelectField } from 'shared/components';
import { UserContactsPreviewComponent } from 'shared/components/contacts-preview/intex';
import {
  ChannelCreateMutationFn,
  UserChannelsPreviewDocument,
  // UserContactsPreviewComponent,
  withChannelCreate,
} from 'shared/graphql/__generated__';

// -- TYPES

interface IChannelCreateHOCProps {
  createChannel: ChannelCreateMutationFn;
}

interface ICreateChannelDialogWrapperProps {
  user: IChatContext['user'];
  setChannel: IChatContext['setChannel'];
  usersFilter: IChatContext['usersFilter'];
}

interface ICreateChannelDialogProps
  extends ICreateChannelDialogWrapperProps,
    IChannelCreateHOCProps {}

interface IDialogContentProps extends ICreateChannelDialogProps {}

interface IDialogContentState {
  data: {
    name: string;
    public: boolean;
    users: string[];
    purpose: string;
  };
  errors: {
    [key in keyof IDialogContentState['data']]?: string;
  };
  submitting: boolean;
}

// -- CONSTANTS

export const CREATE_CHANNEL_DIALOG_ID = 'CREATE_CHANNEL_DIALOG_ID';

// -- MAIN

class DialogContent extends React.PureComponent<
  IDialogContentProps,
  IDialogContentState
> {
  static contextType = ModalContext;
  static id = CREATE_CHANNEL_DIALOG_ID;

  constructor(props: IDialogContentProps) {
    super(props);

    this.state = {
      data: {
        name: '',
        purpose: '',
        public: false,
        users: [],
      },
      errors: {},
      submitting: false,
    };
  }

  render() {
    const { data, errors, submitting } = this.state;
    const { user, usersFilter } = this.props;

    return (
      <DialogForm onSubmit={this.onSubmit}>
        <Dialog.Header title="Create Channel" onClose={this.closeDialog} />

        <Dialog.Body scrollable={true}>
          <Column gap="md">
            <InputField
              label="Name"
              placeholder="Channel's name"
              input={{ name: 'name', value: data.name, onChange: this.onChange }}
              meta={{ error: errors.name, touched: true }}
              stretch={true}
            />

            <InputField
              label="Purpose (optional)"
              placeholder="Channel's purpose"
              input={{ name: 'purpose', value: data.purpose, onChange: this.onChange }}
              stretch={true}
            />

            <UserContactsPreviewComponent
              variables={{
                filter: usersFilter || {
                  id: {
                    not_in: [user ? user.id : ''],
                  },
                },
              }}
            >
              {({ data: resData, loading: queryLoading }) => (
                <UserSelectField
                  label="Send invites to (optional)"
                  placeholder="Search by name"
                  input={{
                    name: 'users',
                    onChange: this.onChangeUserSelect,
                    value: data.users,
                  }}
                  multiple={true}
                  stretch={true}
                  options={
                    queryLoading
                      ? []
                      : get(resData, 'usersList.items', []).map((el: any) => ({
                          label: `${el.firstName} ${el.lastName}`,
                          value: el.id,
                          src: el.avatar && el.avatar.downloadUrl,
                          firstName: el.firstName,
                          lastName: el.lastName,
                        }))
                  }
                />
              )}
            </UserContactsPreviewComponent>

            <Switch
              label="Public"
              name="public"
              value={data.public}
              onChange={this.onChange}
            />
          </Column>
        </Dialog.Body>

        <Dialog.Footer>
          <Button color="primary" type="submit" loading={submitting}>
            Create
          </Button>
        </Dialog.Footer>
      </DialogForm>
    );
  }

  private onSubmit = async (e: any) => {
    e.preventDefault();

    if (!this.props.user || this.state.submitting) {
      return;
    }

    const errors = this.validateData(this.state.data);
    const currentUserId = this.props.user.id;

    if (Object.keys(errors).length > 0) {
      this.setState({
        errors,
      });

      return;
    }

    const { name, purpose, users } = this.state.data;
    const membersCreate = users
      .filter(id => id !== currentUserId)
      .map(id => ({ user: { connect: { id } } }));

    this.setState({
      submitting: true,
    });

    let response;

    try {
      response = await this.props.createChannel({
        variables: {
          data: {
            name,
            purpose,
            public: this.state.data.public,
            members: {
              create: [
                ...membersCreate,
                {
                  user: { connect: { id: currentUserId } },
                },
              ],
            },
          },
        },
        refetchQueries: [getOperationName(UserChannelsPreviewDocument) as string],
      });
    } finally {
      this.setState({
        submitting: false,
      });
    }

    const channelIdentity = get(response, 'data.channelCreate.members.items', []).find(
      (el: any) => el.user.id === currentUserId,
    );

    if (channelIdentity) {
      this.props.setChannel({
        channelIdentityId: channelIdentity.id,
      });

      this.closeDialog();
    }
  };

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

  private onChange = (val: string, e: any) => {
    const targetName = e.target.name;

    this.setState(s => ({
      data: {
        ...s.data,
        [targetName]: val,
      },
      errors: {
        ...s.errors,
        [targetName]: undefined,
      },
    }));
  };

  private onChangeUserSelect = (val: string[]) => {
    this.setState(s => ({
      data: {
        ...s.data,
        users: val,
      },
    }));
  };

  private validateData(data: IDialogContentState['data']) {
    const errors: any = {};

    if (!data.name) {
      errors.name = 'Required';
    }

    return errors;
  }
}

function CreateChannelDialog(props: ICreateChannelDialogProps) {
  return (
    <Dialog id={CREATE_CHANNEL_DIALOG_ID} size="md">
      <DialogContent {...props} />
    </Dialog>
  );
}

export default compose(
  withChannelCreate<ICreateChannelDialogProps, IChannelCreateHOCProps>({
    name: 'createChannel',
  }),
  withContext({ context: ChatContext, keys: ['user', 'setChannel', 'usersFilter'] }),
)(CreateChannelDialog);
