import { put, takeEvery, all, call } from 'redux-saga/effects';

// Apis from parent
import { api } from 'store/apis';
// Action type
import { StoreAction } from 'store/utils/actions';
import { apolloCall } from 'store/utils/sagas';

import { config } from 'config/general';
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import fetch from 'cross-fetch';

import gql from 'graphql-tag';
import actions from './actions';
import selectors from './selectors';
import * as zeus from './graphql-zeus';

const cache = new InMemoryCache();

const client = new ApolloClient({
  link: createHttpLink({
    uri: config.api.messageUrlApollo || config.api.baseUrlApollo || '',
    fetch,
  }),
  cache,
});

const { Zeus, $ } = zeus;

function* getRooms(action) {
  const moreAction = action.type === actions.getRoomsMore.request.constant;

  const zeusQuery = Zeus.query({
    roomsGetMany: [
      {
        pagination: {
          limit: (action.payload && action.payload.limit) || 100,
          skip: (action.payload && action.payload.skip) || 0,
          sort: 'lastMessage DESC',
        },
      },
      {
        _id: true,
        organisationId: true,
        createdAt: true,
        updatedAt: true,
        title: true,
        lastMessage: true,
        stats: {
          unreadCounts: {
            accountId: true,
            count: true,
          },
        },
        getAccounts: {
          _id: true,
          userName: true,
        },
      },
    ],
  });

  const query = gql`
    ${zeusQuery}
  `;

  yield call(apolloCall, {
    query,
    objectReturn: 'roomsGetMany',
    actionRes: moreAction ? actions.getRoomsMore.result.action : actions.getRooms.result.action,
    client,
  });
}

function* getRoomInfo(action) {
  const zeusQuery = Zeus.query({
    roomsGetOne: [
      action.payload || {},
      {
        _id: true,
        organisationId: true,
        createdAt: true,
        updatedAt: true,
        title: true,
        stats: {
          unreadCounts: {
            accountId: true,
            count: true,
          },
        },
        getAccounts: {
          userName: true,
          email: true,
          _id: true,
          profilePicture: {
            large: true,
            medium: true,
            small: true,
          },
        },
      },
    ],
  });

  const query = gql`
    ${zeusQuery}
  `;

  yield call(apolloCall, {
    query,
    objectReturn: 'roomsGetOne',
    actionRes: actions.getRoomInfo.result.action,
    client,
  });
}

function* getRoomMessages(action) {
  const zeusQuery = Zeus.query({
    roomsGetOne: [
      (action.payload && action.payload.id && { id: action.payload.id }) || {},
      {
        getMessages: [
          (action.payload &&
            action.payload.pagination && { pagination: action.payload.pagination }) ||
            {},
          {
            _id: true,
            message: true,
            createdAt: true,
            sentBy: true,
            readBy: {
              accountId: true,
              readAt: true,
            },
            file: {
              large: true,
              medium: true,
              small: true,
            },
          },
        ],
      },
    ],
  });

  const query = gql`
    ${zeusQuery}
  `;

  yield call(apolloCall, {
    query,
    objectReturn: 'roomsGetOne.getMessages',
    actionRes: actions.getRoomMessage.result.action,
    noLoading: action.payload.noLoading || false,
    callback: action.payload.callback,
    client,
  });
}

function* createRoom(action) {
  const zeusMutation = Zeus.mutation({
    roomsCreateOne: [
      {
        input: $`data`,
      },
      {
        _id: true,
        organisationId: true,
        createdAt: true,
        updatedAt: true,
        title: true,
        lastMessage: true,
        stats: {
          unreadCounts: {
            accountId: true,
            count: true,
          },
        },
        getAccounts: {
          _id: true,
          userName: true,
        },
      },
    ],
  });

  const mutate = gql`
    ${zeusMutation}
  `;

  yield call(apolloCall, {
    mutate,
    data: action.payload,
    objectReturn: 'roomsCreateOne',
    actionRes: actions.createRoom.result.action,
    callback: action.payload.callback,
    client,
  });
}

function* createMessage(action) {
  const zeusMutation = Zeus.mutation({
    roomsAddOneMessage: [
      {
        input: $`data`,
      },
      {
        _id: true,
        message: true,
        sentBy: true,
        createdAt: true,
        readBy: {
          accountId: true,
          readAt: true,
        },
        file: {
          large: true,
          medium: true,
          small: true,
        },
      },
    ],
  });

  const mutate = gql`
    ${zeusMutation}
  `;

  yield call(apolloCall, {
    mutate,
    data: action.payload,
    objectReturn: 'roomsAddOneMessage',
    actionRes: actions.createMessage.result.action,
    callback: action.payload.callback,
    client,
  });
}

function* removePeopleRoom(action) {
  const zeusMutation = Zeus.mutation({
    roomsRemovePeople: [
      {
        input: $`data`,
      },
      {
        _id: true,
        organisationId: true,
        createdAt: true,
        updatedAt: true,
        title: true,
        stats: {
          unreadCounts: {
            accountId: true,
            count: true,
          },
        },
        getAccounts: {
          userName: true,
          email: true,
          _id: true,
          profilePicture: {
            large: true,
            medium: true,
            small: true,
          },
        },
      },
    ],
  });

  const mutate = gql`
    ${zeusMutation}
  `;

  yield call(apolloCall, {
    mutate,
    data: action.payload,
    objectReturn: 'roomsRemovePeople',
    actionRes: actions.removePeopleRoom.result.action,
    callback: action.payload.callback,
    client,
  });
}

function* addPeopleRoom(action) {
  const zeusMutation = Zeus.mutation({
    roomsAddPeople: [
      {
        input: $`data`,
      },
      {
        _id: true,
        organisationId: true,
        createdAt: true,
        updatedAt: true,
        title: true,
        stats: {
          unreadCounts: {
            accountId: true,
            count: true,
          },
        },
        getAccounts: {
          userName: true,
          email: true,
          _id: true,
          profilePicture: {
            large: true,
            medium: true,
            small: true,
          },
        },
      },
    ],
  });

  const mutate = gql`
    ${zeusMutation}
  `;

  yield call(apolloCall, {
    mutate,
    data: action.payload,
    objectReturn: 'roomsAddPeople',
    actionRes: actions.addPeopleRoom.result.action,
    callback: action.payload.callback,
    client,
  });
}

function* roomSeen(action) {
  const zeusMutation = Zeus.mutation({
    roomsMarkAllMessageAsRead: [
      {
        roomId: $`id`,
      },
      {
        _id: true,
        stats: {
          unreadCounts: {
            accountId: true,
            count: true,
          },
        },
      },
    ],
  });

  const mutate = gql`
    ${zeusMutation}
  `;

  yield call(apolloCall, {
    mutate,
    data: action.payload,
    objectReturn: 'roomsMarkAllMessageAsRead',
    actionRes: actions.roomSeen.result.action,
    callback: action.payload.callback,
    noLoading: true,
    client,
  });
}

function* messageWatchers() {
  yield all([
    yield takeEvery(actions.getRooms.request.constant, getRooms),
    yield takeEvery(actions.getRoomsMore.request.constant, getRooms),
    yield takeEvery(actions.getRoomInfo.request.constant, getRoomInfo),
    yield takeEvery(actions.getRoomMessage.request.constant, getRoomMessages),
    yield takeEvery(actions.createRoom.request.constant, createRoom),
    yield takeEvery(actions.createMessage.request.constant, createMessage),
    yield takeEvery(actions.removePeopleRoom.request.constant, removePeopleRoom),
    yield takeEvery(actions.addPeopleRoom.request.constant, addPeopleRoom),
    yield takeEvery(actions.roomSeen.request.constant, roomSeen),
  ]);
}

export default function* saga() {
  yield call(messageWatchers);
}
