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

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

import { config, zeus } from 'config/general';

import { gqlConvert } from 'store/utils/adminHelpers';
import gql from 'graphql-tag';
import { genericList } from 'store/genericApollo/sagas';
import genericApollo from 'store/genericApollo';
import { loadContent } from 'store/content/sagas';
import actions from './actions';
import selectors from './selectors';
/**
 * Profile
 */
const { Zeus, $ } = zeus;

function* userProfile(action: StoreAction): void {
  const payload = (action && action.payload) || {};

  const options = config.accountOptions;

  if (options.apollo) {
    const model = options.profileFields;

    if (!model) {
      console.log('no account model', options);
      return null;
    }

    const resourceName = options.resource;

    const outputModel = gqlConvert(model, options);

    const apiInput = {};

    let zeusQuery;
    try {
      zeusQuery = Zeus.query({
        [resourceName]: [apiInput, outputModel],
      });
    } catch (error) {
      console.log('error get me', error);
      return null;
    }

    const query = gql`
      ${zeusQuery}
    `;

    const profile = yield call(apolloCall, {
      objectReturn: resourceName,
      query,
      actionRes: actions.profile.result.action,
      noLoading: payload.noLoading,
      callback: payload.callback,
      callbackError: payload.callbackError,
    });

    return profile;
  }
  const profile = yield call(apiCall, {
    api: api.account.profile,
    data: payload.data || payload,
    actionRes: actions.profile.result.action,
    noLoading: payload.noLoading,
    callback: payload.callback,
    callbackError: payload.callbackError,
  });

  return profile;
}

function* loadAccountResource(action) {
  const payload = (action && action.payload) || {};

  const options = config.accountOptions;

  const accountResourceOptions = options.accountResourceOptions;
  if (!accountResourceOptions) {
    return;
  }

  console.log('accountResourceOptions', accountResourceOptions);

  // Profile field has priority over additional api call
  if (accountResourceOptions.profileField) {
    const profile = yield select(selectors.getProfile);

    if (profile[accountResourceOptions.profileField]) {
      let resources = profile[accountResourceOptions.profileField];
      if (!Array.isArray(resources)) resources = [resources];

      yield put(actions.loadAccountResource.result.action(resources, 'fulfilled'));
    }
    return;
  }

  if (!accountResourceOptions.apollo) {
    console.error('No account resource handling for not apollo projects', accountResourceOptions);
    return;
  }

  // Use the same generic list => so we have a construc action object

  yield call(
    genericList,
    genericApollo.actions.list.request.action({
      options: accountResourceOptions,
      callback: payload.callback,
    }),
    { limit: 100, skip: 0 },
    actions.loadAccountResource.result.action,
  );
}

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

  const options = config.accountOptions;

  const data = payload.data;

  if (options.apollo) {
    const model = options.profileFields;

    const resourceName = options.resourceUpdate;

    const outputModel = gqlConvert(model, options);

    let zeusMutation;
    try {
      zeusMutation = Zeus.mutation({
        [resourceName]: [
          {
            input: $`data`,
          },
          outputModel,
        ],
      });
    } catch (error) {
      console.log('error get me', error);
      return;
    }

    const mutate = gql`
      ${zeusMutation}
    `;

    yield apolloCall({
      mutate,
      objectReturn: resourceName,
      data,
      callback: payload && payload.callback,
      actionRes: actions.updateProfile.result.action,
    });
  } else {
    yield call(apiCall, {
      api: api.account.updateProfile,
      data,
      callback: payload && payload.callback,
      actionRes: actions.updateProfile.result.action,
    });
  }
}

/**
 * Signup steps
 */
function* signup(action: StoreAction): void {
  yield call(apiCall, {
    api: api.account.signup,
    data: action.payload,
    actionRes: actions.signup.result.action,
  });
}

export function* userInit(action): void {
  const content = yield select((state: StoreState) => state.content.raw);
  const payload = (action && action.payload) || {};

  const callback = payload.callback;

  delete payload.callback;

  const profile = yield call(userProfile, action);

  // If any
  if (profile && profile.types && profile.types.includes('admin')) {
    yield call(loadAccountResource);
  } else if (profile && profile.myOrganisations) {
    yield put(actions.loadAccountResource.result.action(profile.myOrganisations));
  }

  if (!content) yield call(loadContent);

  if (typeof callback === 'function') callback(profile);
}

function* accountWatchers(): void {
  yield all([
    yield takeEvery(actions.init.request.constant, userInit),
    yield takeEvery(actions.profile.request.constant, userProfile),
    yield takeEvery(actions.updateProfile.request.constant, updateProfile),
    // signup
    yield takeEvery(actions.signup.request.constant, signup),

    yield takeEvery(actions.loadAccountResource.request.constant, loadAccountResource),
  ]);
}

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