/*
 * Copyright (c) 2016-present, Parse, LLC
 * All rights reserved.
 *
 * This source code is licensed under the license found in the LICENSE file in
 * the root directory of this source tree.
 */
import keyMirror from 'lib/keyMirror';
import { Map } from 'immutable';
import { registerStore } from 'lib/stores/StoreManager';

export const ActionTypes = keyMirror([
  'FETCH',
  'CREATE_CLASS',
  'DROP_CLASS',
  'ADD_COLUMN',
  'DROP_COLUMN',
  'SET_CLP',
]);

// Schema state should be an Immutable Map with the following fields:
//   - lastFetch: the last time all data was fetched from the server
//   - classes: An Immutable Map of class names to Maps of column => type
//   - CLPs: An Immutable Map of class names to CLPs

function SchemaStore(state, action) {
  switch (action.type) {
    case ActionTypes.FETCH:
      if (state && new Date() - state.get('lastFetch') < 60000) {
        return Promise.resolve(state);
      }
      return action.app
        .apiRequest('GET', 'schemas', {}, { useMasterKey: true })
        .then(({ results }) => {
          const classes = {};
          const CLPs = {};
          if (results) {
            results.forEach(({ className, fields, classLevelPermissions }) => {
              classes[className] = Map(fields);
              CLPs[className] = Map(classLevelPermissions);
            });
          }
          return Map({
            lastFetch: new Date(),
            classes: Map(classes),
            CLPs: Map(CLPs),
          });
        });
    case ActionTypes.CREATE_CLASS:
      return action.app
        .apiRequest(
          'POST',
          'schemas/' + action.className,
          { className: action.className },
          { useMasterKey: true }
        )
        .then(({ fields, classLevelPermissions }) => {
          return state
            .setIn(['classes', action.className], Map(fields))
            .setIn(['CLPs', action.className], Map(classLevelPermissions));
        });
    case ActionTypes.DROP_CLASS:
      return action.app
        .apiRequest('DELETE', 'schemas/' + action.className, {}, { useMasterKey: true })
        .then(() => {
          return state.deleteIn(['classes', action.className]).deleteIn(['CLPs', action.className]);
        });
    case ActionTypes.ADD_COLUMN:
      const newField = {
        [action.name]: {
          type: action.columnType,
          required: action.required,
          defaultValue: action.defaultValue,
        },
      };
      if (action.columnType === 'Pointer' || action.columnType === 'Relation') {
        newField[action.name].targetClass = action.targetClass;
      }
      return action.app
        .apiRequest(
          'PUT',
          'schemas/' + action.className,
          { className: action.className, fields: newField },
          { useMasterKey: true }
        )
        .then(({ fields }) => {
          return state.setIn(['classes', action.className], Map(fields));
        });
    case ActionTypes.DROP_COLUMN:
      const droppedField = {
        [action.name]: {
          __op: 'Delete',
        },
      };
      return action.app
        .apiRequest(
          'PUT',
          'schemas/' + action.className,
          { className: action.className, fields: droppedField },
          { useMasterKey: true }
        )
        .then(({ fields }) => {
          return state.setIn(['classes', action.className], Map(fields));
        });
    case ActionTypes.SET_CLP:
      return action.app
        .apiRequest(
          'PUT',
          'schemas/' + action.className,
          { classLevelPermissions: action.clp },
          { useMasterKey: true }
        )
        .then(({ classLevelPermissions, className }) => {
          return state.setIn(['CLPs', className], Map(classLevelPermissions));
        });
  }
}

registerStore('Schema', SchemaStore);
