/**
 * <%= pascalCase(singularDomainName) %> Reducer
 */

import {Update} from '@ngrx/entity';
import {hasAnyItems, isItemDefined} from '@zionapps/core';
import {<%= pascalCase(pluralDomainName) %>Actions} from './<%= paramCase(pluralDomainName) %>.actions';
import {<%= pascalCase(singularDomainName) %>, <%= pascalCase(pluralDomainName) %>Domain} from './<%= paramCase(pluralDomainName) %>.domain';
import {<%= camelCase(pluralDomainName) %>Adapter, canSave<%= pascalCase(singularDomainName) %>, canSave<%= pascalCase(singularDomainName) %>List} from './<%= paramCase(pluralDomainName) %>.utils';

const initialState: <%= pascalCase(pluralDomainName) %>Domain.State = <%= camelCase(pluralDomainName) %>Adapter.getInitialState({
  entities: {},
  ids: [],
  lastResult: null,
  loaded: false,
  currentId: null,
});

export function <%= camelCase(pluralDomainName) %>Reducer(state = initialState, action: <%= pascalCase(pluralDomainName) %>Actions.Union): <%= pascalCase(pluralDomainName) %>Domain.State {
  switch (action.type) {
    case <%= pascalCase(pluralDomainName) %>Actions.Type.AddAll: {
      const { payload } = action;
      return canSave<%= pascalCase(singularDomainName) %>List(payload) ? <%= camelCase(pluralDomainName) %>Adapter.addAll(payload, state) : state;
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.AddMany: {
      const { payload } = action;
      return canSave<%= pascalCase(singularDomainName) %>List(payload) ? <%= camelCase(pluralDomainName) %>Adapter.addMany(payload, state) : state;
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.AddOne:
    case <%= pascalCase(pluralDomainName) %>Actions.Type.UpdateOne: {
      const { payload } = action;
      if (canSave<%= pascalCase(singularDomainName) %>(payload)) {
        const { id, ...changes } = payload;
        const { entities } = state;
        if (isItemDefined(entities) && isItemDefined(entities[id])) {
          return <%= camelCase(pluralDomainName) %>Adapter.updateOne({ changes, id }, state);
        } else {
          return <%= camelCase(pluralDomainName) %>Adapter.addOne(payload, state);
        }
      }
      return state;
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.ClearCurrentId: {
      return { ...state, currentId: null };
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.RemoveAll: {
      return { ...<%= camelCase(pluralDomainName) %>Adapter.removeAll(state), currentId: null };
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.RemoveMany: {
      const { payload } = action;
      return hasAnyItems(payload) ? <%= camelCase(pluralDomainName) %>Adapter.removeMany(payload, state) : state;
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.RemoveOne: {
      const { payload } = action;
      return <%= camelCase(pluralDomainName) %>Adapter.removeOne(payload, state);
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.ReportLastResult: {
      const { payload } = action;
      return { ...state, lastResult: payload };
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.SetCurrentId: {
      const { payload } = action;
      return { ...state, currentId: payload };
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.UpdateMany: {
      const { payload } = action;
      const updates = canSave<%= pascalCase(singularDomainName) %>List(payload) ? payload.map((item: <%= pascalCase(singularDomainName) %>): Update<<%= pascalCase(singularDomainName) %>> => {
        const { id, ...changes } = item;
        return { id, changes };
      }) : [];
      return <%= camelCase(pluralDomainName) %>Adapter.updateMany(updates, state);
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.UpsertMany: {
      const { payload } = action;
      const updates = canSave<%= pascalCase(singularDomainName) %>List(payload) ? payload.map((item: <%= pascalCase(singularDomainName) %>): Update<<%= pascalCase(singularDomainName) %>> => {
        const { id, ...changes } = item;
        return { id, changes };
      }) : [];
      return <%= camelCase(pluralDomainName) %>Adapter.upsertMany(updates, state);
    }
    case <%= pascalCase(pluralDomainName) %>Actions.Type.UpsertOne: {
      const { payload } = action;
      if (canSave<%= pascalCase(singularDomainName) %>(payload)) {
        const { id, ...changes } = payload;
        return <%= camelCase(pluralDomainName) %>Adapter.upsertOne({ changes, id }, state);
      }
      return state;
    }
    default: {
      return state;
    }
  }
}
