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

import { apiCall, apolloCall } from 'store/utils/sagas';
import { api } from 'store/apis';
import config from 'config/general';
import gql from 'graphql-tag';
import { deepOmit } from 'store/utils/helper';
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import fetch from 'cross-fetch';
import actions from './actions';
import selectors from './selectors';

const cache = new InMemoryCache();

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

function* cmsList(action): void {
  const payload = action.payload || {};

  if (config.cmsApollo) {
    const name = config.cmsQueryName;

    const query = gql`
      {
        ${name}(pagination: { skip: 0, limit: 1000 }) {
          _id
          title
          label
          content
          position
        }
      }
    `;

    yield call(apolloCall, {
      query,
      objectReturn: `${name}`,
      noLoading: payload.noLoading,
      noFeedback: payload.noFeedback,
      callback: payload.callback,
      actionSuccess: actions.list.result.action,
      client,
    });
  } else {
    yield call(apiCall, {
      api: api.cms.list,
      data: {
        limit: 1000,
      },
      noLoading: payload.noLoading,
      noFeedback: payload.noFeedback,
      callback: payload.callback,
      actionSuccess: actions.list.result.action,
    });
  }
}

function* cmsUpdate(action): void {
  const payload = action.payload;
  const data = payload.data;

  // to make sure to no send
  delete data.toComplete;

  let request;

  if (config.cmsApollo) {
    const mutate = gql`
      mutation edit($data: EditPageInput!, $id: String!) {
        pagesEditOne(input: $data, id: $id) {
          _id
          title
          label
          content
          position
        }
      }
    `;

    request = yield call(apolloCall, {
      mutate,
      objectReturn: 'pagesEditOne',
      data: {
        id: payload.id,
        // only first level omit
        data: deepOmit(
          payload.data,
          ['filterMatch', 'hide', 'stats', 'state', '__typename', '_id'],
          false,
        ),
      },
      callback: payload && payload.callback,
      success: 'admin.messages.pageUpdateSuccess',
      actionRes: actions.update.result.action,
      client,
    });
  } else {
    if (data.contentParsed) {
      data.contentParsed = undefined;
    }

    request = yield call(apiCall, {
      api: api.cms.update,
      id: payload.id,
      data,
      callback: payload && payload.callback,
      success: 'admin.messages.pageUpdateSuccess',
      actionRes: actions.update.result.action,
    });
  }

  if (request && !request.error) {
    const cms = yield select(selectors.getCMSData);
    if (cms) {
      yield put(content.actions.content.result.action(cms, 'fulfilled'));
    }
  }
}

function* cmsAdd(action): void {
  const payload = action.payload;

  if (config.cmsApollo) {
    const mutate = gql`
      mutation add($data: NewPageInput!) {
        pagesAddOne(input: $data) {
          _id
          title
          label
          content
          position
        }
      }
    `;

    yield call(apolloCall, {
      mutate,
      objectReturn: 'pagesAddOne',
      data: {
        // only first level omit
        data: deepOmit(payload.data, 'state'),
      },
      success: 'Page added with success',
      callback: payload && payload.callback,
      actionRes: actions.add.result.action,
      client,
    });
  } else {
    yield call(apiCall, {
      api: api.cms.add,
      data: payload.data,
      success: 'Page added with success',
      callback: payload && payload.callback,
      actionRes: actions.add.result.action,
    });
  }
}

function* cmsDelete(action): void {
  const payload = action.payload;
  if (config.cmsApollo) {
    const mutate = gql`
      mutation delete($id: String!) {
        pagesDeleteOne(id: $id) {
          _id
          title
          label
          content
          position
        }
      }
    `;

    yield call(apolloCall, {
      mutate,
      objectReturn: 'pagesDeleteOne',
      data: payload,
      success: 'Page deleted with success',
      callback: payload && payload.callback,
      actionRes: (resp, status) => actions.delete.result.action(payload.id, status),
      client,
    });
  } else {
    yield call(apiCall, {
      api: api.cms.delete,
      id: payload.id,
      success: 'Page deleted with success',
      callback: payload && payload.callback,
      actionRes: (resp, status) => actions.delete.result.action(payload.id, status),
    });
  }
}

function* cmsSync(action): void {
  yield call(apiCall, {
    api: api.cms.syncContent,
    env: action.payload,
    success: 'Content Updated',
    actionRes: actions.syncContent.result.action,
  });
}

function* cmsWatchers(): void {
  yield all([
    yield takeEvery(actions.list.request.constant, cmsList),
    yield takeEvery(actions.update.request.constant, cmsUpdate),
    yield takeEvery(actions.add.request.constant, cmsAdd),
    yield takeEvery(actions.delete.request.constant, cmsDelete),
    yield takeEvery(actions.syncContent.request.constant, cmsSync),
  ]);
}

export default function* saga(): void {
  yield call(cmsWatchers);
}
