import {
  createAsyncThunk,
  createEntityAdapter,
  createSelector,
  createSlice,
  EntityState,
  PayloadAction
} from '@reduxjs/toolkit';

export const <%= constantName %>_FEATURE_KEY = '<%= propertyName %>';

/*
 * Update these interfaces according to your requirements.
 */
export interface <%= className %>Entity {
  id: number;
}

export interface <%= className %>State extends EntityState<<%= className %>Entity> {
  loadingStatus: 'not loaded' | 'loading' | 'loaded' | 'error';
  error?: string | null;
}

export const <%= propertyName %>Adapter = createEntityAdapter<<%= className %>Entity>();

/**
 * Export an effect using createAsyncThunk from
 * the Redux Toolkit: https://redux-toolkit.js.org/api/createAsyncThunk
 *
 * e.g.
 * ```
 * import React, { useEffect } from 'react';
 * import { useDispatch } from 'react-redux';
 *
 * // ...
 *
 * const dispatch = useDispatch();
 * useEffect(() => {
 *   dispatch(fetch<%= className %>())
 * }, [dispatch]);
 * ```
 */
export const fetch<%= className %> = createAsyncThunk<<%= className %>Entity[]>(
  '<%= propertyName %>/fetchStatus',
  async (_, thunkAPI) => {
    /**
     * Replace this with your custom fetch call.
     * For example, `return myApi.get<%= className %>s()`;
     * Right now we just return an empty array.
     */
    return Promise.resolve([]);
  }
);

export const initial<%= className %>State: <%= className %>State = <%= propertyName %>Adapter.getInitialState({
  loadingStatus: 'not loaded',
  error: null
});

export const <%= propertyName %>Slice = createSlice({
  name: <%= constantName %>_FEATURE_KEY,
  initialState: initial<%= className %>State,
  reducers: {
    add: <%= propertyName %>Adapter.addOne,
    remove: <%= propertyName %>Adapter.removeOne
    // ...
  },
  extraReducers: builder => {
    builder
      .addCase(fetch<%= className %>.pending, (state: <%= className %>State) => {
        state.loadingStatus = 'loading';
      })
      .addCase(fetch<%= className %>.fulfilled, (state: <%= className %>State, action: PayloadAction<<%= className %>Entity[]>) => {
        <%= propertyName %>Adapter.setAll(state, action.payload);
        state.loadingStatus = 'loaded';
      })
      .addCase(fetch<%= className %>.rejected, (state: <%= className %>State, action) => {
        state.loadingStatus = 'error';
        state.error = action.error.message;
      });
  }
});

/*
 * Export reducer for store configuration.
 */
export const <%= propertyName %>Reducer = <%= propertyName %>Slice.reducer;

/*
 * Export action creators to be dispatched. For use with the `useDispatch` hook.
 *
 * e.g.
 * ```
 * import React, { useEffect } from 'react';
 * import { useDispatch } from 'react-redux';
 *
 * // ...
 *
 * const dispatch = useDispatch();
 * useEffect(() => {
 *   dispatch(<%= propertyName %>Actions.add({ id: 1 }))
 * }, [dispatch]);
 * ```
 *
 * See: https://react-redux.js.org/next/api/hooks#usedispatch
 */
export const <%= propertyName %>Actions = <%= propertyName %>Slice.actions;

/*
 * Export selectors to query state. For use with the `useSelector` hook.
 *
 * e.g.
 * ```
 * import { useSelector } from 'react-redux';
 *
 * // ...
 *
 * const entities = useSelector(selectAll<%= className %>);
 * ```
 *
 * See: https://react-redux.js.org/next/api/hooks#useselector
 */
const { selectAll, selectEntities } = <%= propertyName %>Adapter.getSelectors();

export const get<%= className %>State = (rootState: {[<%= constantName %>_FEATURE_KEY]: <%= className %>State }): <%= className %>State => rootState[<%= constantName %>_FEATURE_KEY];

export const selectAll<%= className %> = createSelector(get<%= className %>State, selectAll);

export const select<%= className %>Entities = createSelector(get<%= className %>State, selectEntities);
